/*
 * The MIT License (MIT)
 *
 * FXGL - JavaFX Game Library
 *
 * Copyright (c) 2015-2016 AlmasB (almaslvl@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.almasb.fxgl.texture;

import com.almasb.fxgl.app.FXGL;
import com.almasb.fxgl.event.FXGLEvent;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.geometry.Rectangle2D;
import javafx.scene.image.Image;
import javafx.util.Duration;

/**
 * A texture which is statically animated, i.e.
 * loops through its frames constantly
 *
 * @author Almas Baimagambetov (AlmasB) (almaslvl@gmail.com)
 */
public final class StaticAnimatedTexture extends Texture {

    private Timeline timeline;

    /**
     * @param image    actual image
     * @param frames   number of frames in sprite sheet
     * @param duration duration of the animation
     */
    StaticAnimatedTexture(Image image, int frames, Duration duration) {
        super(image);

        final double frameW = image.getWidth() / frames;

        this.setFitWidth(frameW);
        this.setFitHeight(image.getHeight());

        this.setViewport(new Rectangle2D(0, 0, frameW, image.getHeight()));

        SimpleIntegerProperty frameProperty = new SimpleIntegerProperty();
        frameProperty.addListener((obs, old, newValue) -> {
            this.setViewport(new Rectangle2D(newValue.intValue() * frameW, 0, frameW, image.getHeight()));
        });

        timeline = new Timeline(new KeyFrame(duration, new KeyValue(frameProperty, frames - 1)));
        timeline.setCycleCount(Timeline.INDEFINITE);
        timeline.play();

        FXGL.getEventBus().addEventHandler(FXGLEvent.PAUSE, e -> {
            timeline.pause();
        });

        FXGL.getEventBus().addEventHandler(FXGLEvent.RESUME, e -> {
            timeline.play();
        });
    }
}

@@ -1299,16 +1299,146 @@
 LEvent;%0A
+import com.almasb.fxgl.time.LocalTimer;%0Aimport com.almasb.fxgl.time.UpdateEvent;%0Aimport com.almasb.fxgl.time.UpdateEventListener;%0A
 import j
@@ -1902,40 +1902,328 @@
 ure 
-%7B%0A%0A    private Timeline timeline
+implements UpdateEventListener %7B%0A%0A    // TODO: can we replace with a single AnimationChannel?%0A    // Dynamic has similar code, we need to apply DRY%0A    private int currentFrame = 0;%0A    private double timePerAnimationFrame = 0;%0A    private LocalTimer animationTimer;%0A%0A    private int maxFrames;%0A    private double frameW
 ;%0A%0A 
@@ -2485,21 +2485,8 @@
     
-final double 
 fram
@@ -2688,134 +2688,378 @@
     
-SimpleIntegerProperty frameProperty = new SimpleIntegerProperty();%0A        frameProperty.addListener((obs, old, newValue) -%3E %7B
+maxFrames = frames;%0A        timePerAnimationFrame = duration.toSeconds() / frames;%0A%0A        animationTimer = FXGL.newLocalTimer();%0A%0A        // TODO: clean listener%0A        FXGL.getMasterTimer().addUpdateListener(this);%0A    %7D%0A%0A    @Override%0A    public void onUpdateEvent(UpdateEvent event) %7B%0A        if (animationTimer.elapsed(Duration.seconds(timePerAnimationFrame))) %7B%0A
 %0A   
@@ -3059,37 +3059,32 @@
  %7B%0A%0A            
-this.
 setViewport(new 
@@ -3099,27 +3099,20 @@
 e2D(
-newValue.intValue()
+currentFrame
  * f
@@ -3125,32 +3125,29 @@
  0, frameW, 
-image.ge
+getFi
 tHeight()));
@@ -3159,393 +3159,157 @@
     
-%7D);%0A%0A        timeline = new Timeline(new KeyFrame(duration, new KeyValue(frameProperty, frames - 1)));%0A        timeline.setCycleCount(Timeline.INDEFINITE);%0A        timeline.play();%0A%0A        FXGL.getEventBus().addEventHandler(FXGLEvent.PAUSE, e -%3E %7B%0A            timeline.pause();%0A        %7D);%0A%0A        FXGL.getEventBus().addEventHandler(FXGLEvent.RESUME, e -%3E %7B%0A            timeline.play
+    currentFrame++;%0A%0A            if (currentFrame == maxFrames) %7B%0A                currentFrame = 0;%0A            %7D%0A%0A            animationTimer.capture
 ();%0A
@@ -3317,18 +3317,16 @@
        %7D
-);
 %0A    %7D%0A%7D

use own animation tick