Engine.SimpleTween = class
{

    constructor(onUpdate, tweenFunc, start, end, time, toInt)
    {
        this.t; //current time
        this.c; //delta
        this.b; //start value
        this.d; //duration

        this.tweenValue;
        this.toInt = false;

        this.instant = false;

        this.MaxTime = -1;

        this.active = false;

        this.onFinish = null;
        this.onUpdate = null;
        this.loop = false;

        this.ignoreFirstUpdate = true;
        this.timeScale = 1;

        this.paused = 0;

        this.thisTween = null;

        if (onUpdate !== undefined)
        {
            this.init(onUpdate, tweenFunc, start, end, time, toInt);
        }

    }

    pause()
    {
        this.paused++;
    }

    resume()
    {
        if (this.paused > 0) this.paused--;
    }
	
	get isPaused() { return this.paused > 0; }
	
	forceFinish()
	{
		this.t = this.d;
	}

    stop()
    {
        if (this.onStop != null) this.onStop();

        this.active = false;
        this.onFinish = null;
        this.onUpdate = null;
        Engine.EnterFrameManagerInstance.remove(this);
    }

    init(onUpdate, tweenFunc, start, end, time, toInt = false)
    {
        if (this.active) this.stop();
        this.onUpdate = onUpdate;
        this.toInt = toInt;

        this.tweenValue = start;

        this.thisTween = tweenFunc;

        this.t = 0;
        this.c = end - start;
        this.b = start;
        this.d = time;

        this.instant = (this.d == 0);
        Engine.EnterFrameManagerInstance.add(this, (timeElapsed) => { this.update(timeElapsed); });
        this.active = true;

        this.ignoreFirstUpdate = true;
    }

    update(timeElapsed)
    {
        if (this.ignoreFirstUpdate)
        {
            this.ignoreFirstUpdate = false;
            return;
        }

        if (this.MaxTime != -1) timeElapsed = Math.min(timeElapsed, this.MaxTime);

        if (this.paused > 0) return;
        if (!this.active) return;

        this.t += (timeElapsed * this.timeScale);

        if (this.t >= this.d) this.t = this.d;

        var val = 0;
        val = this.thisTween(this.instant ? 1.0 : this.t, this.b, this.c, this.instant ? 1.0 : this.d);
        
        var intVal = Math.floor(val);
        if (this.toInt) val = intVal;

        this.tweenValue = val;

        if (this.onUpdate != null) this.onUpdate(this.tweenValue);

        if (this.t == this.d)
        {
            if (this.loop)
            {
                this.t = 0;
            }
            else
            {
                this.active = false;
                Engine.EnterFrameManagerInstance.remove(this);
            }
            if (this.onFinish) this.onFinish();

        }

    }

    forceUpdateCall()
    {
        if (this.active)
        {
            if (this.onUpdate != null) this.onUpdate(this.tweenValue);
        }
    }

    static sineWaveIn(t, b, c, d)
    {
        var param = (t / d);
        var s = (-(Math.pow(((param-0.774)*1.4), 2) )) + 1.1;
        return c * s + b;
    }

    static easeLinear(t, b, c, d)
    {
        return c * t / d + b;
    }

    static quadEaseIn(t, b, c, d)
    {
        return c * (t /= d) * t + b;
    }

    static quadEaseOut(t, b, c, d)
    {
        return -c * (t /= d) * (t - 2) + b;
    }

    static quadEaseInOut(t, b, c, d)
    {
        if ((t /= d * 0.5) < 1) return c * 0.5 * t * t + b;
        return -c * 0.5 * ((--t) * (t - 2) - 1) + b;
    }

    static strongEaseIn(t, b, c, d)
    {
        return c * (t /= d) * t * t * t * t + b;
    }

    static strongEaseOut(t, b, c, d)
    {
        return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
    }

    static strongEaseInOut(t, b, c, d)
    {
        if ((t /= d * 0.5) < 1) return c * 0.5 * t * t * t * t * t + b;
        return c * 0.5 * ((t -= 2) * t * t * t * t + 2) + b;
    }

}