/*
 * Copyright 2021-2023 MicroEJ Corp. All rights reserved.
 * This library is provided in source code for use, modification and test, subject to license terms.
 * Any modification of the source code will break MicroEJ Corp. warranties on the whole library.
 */
package ej.widget.motion;

import ej.bon.Util;
import ej.motion.Motion;
import ej.mwt.animation.Animation;
import ej.mwt.animation.Animator;

/**
 * A motion animation allows to associate a {@link Motion} and an {@link Animation}.
 */
public class MotionAnimation {

	private final Animator animator;
	private final Motion motion;
	private final MotionAnimationListener listener;
	private final Animation animation;

	private long startTime;
	private int lastValue;

	/**
	 * Creates a motion animation.
	 *
	 * @param animator
	 *            the animator instance with which the animation will be executed.
	 * @param motion
	 *            the motion of the animation.
	 * @param listener
	 *            the listener to notify during the animation.
	 */
	public MotionAnimation(Animator animator, Motion motion, MotionAnimationListener listener) {
		this.animator = animator;
		this.motion = motion;
		this.listener = listener;
		this.animation = new Animation() {
			@Override
			public boolean tick(long currentTimeMillis) {
				return MotionAnimation.this.tick(currentTimeMillis);
			}
		};
	}

	/**
	 * Starts (or restarts) this motion animation.
	 */
	public void start() {
		this.startTime = Util.platformTimeMillis();
		this.lastValue = this.motion.getStartValue();
		this.animator.startAnimation(this.animation);
	}

	/**
	 * Stops this motion animation.
	 *
	 * @throws IllegalStateException
	 *             if this method is called in an other thread than the MicroUI thread or during an animation tick.
	 */
	public void stop() {
		this.animator.stopAnimation(this.animation);
	}

	private boolean tick(long currentTimeMillis) {
		long elapsedTime = currentTimeMillis - this.startTime;
		boolean finished = (elapsedTime >= this.motion.getDuration());
		int value = this.motion.getValue(elapsedTime);
		if (value != this.lastValue || finished) {
			this.listener.tick(value, finished);
			this.lastValue = value;
		}
		return !finished;
	}
}
