Engine.MultiTransformTweener = class
{
	constructor()
	{
		this.finalCallback = null;
		this.transforms = null;
		this.tweens = new Engine.ObjectPool(Engine.SimpleTween);
		this.currentTweens = [];//new List<Engine.SimpleTween>();
		this.currentTransform = null;
		this.drawable = null;
		this.timeFactor = 1;
		this.moveFactor = 1;
		this.completeTweenCounter = 0;
		this.position = 0;
	}

	/// <summary>
	/// Initialize the values for use
	/// </summary>
	/// <param name="drawable"></param>
	/// <param name="transforms"></param>
	init(drawable /*IAnimationActor*/, transforms /*List<Transform>*/, moveFactor /*float*/, timeFactor /*float*/)
	{
		if (moveFactor === undefined) moveFactor = 1;
		if (timeFactor === undefined) timeFactor = 1;

		this.finalCallback = null;
		this.position = 0;
		this.transforms = transforms;
		this.currentTransform = transforms[this.position];
		
		this.moveFactor = moveFactor;
		this.timeFactor = timeFactor;
		this.drawable = drawable;
		
		this.applyTransform(this.currentTransform);
		
		this.createNextTweens();
	}

	/// <summary>
	/// Apply the transform to the item we are workign with
	/// </summary>
	/// <param name="transform"></param>
	applyTransform(transform /*Transform*/)
	{
		if (transform.x != null) this.drawable.x = transform.x;
		if (transform.y != null) this.drawable.y = transform.y;
		if (transform.scaleX != null) this.drawable.scale.x = transform.scaleX;
		if (transform.scaleY != null) this.drawable.scale.y = transform.scaleY;
		if (transform.rotation != null) this.drawable.rotation = transform.rotation;
	}

	/// <summary>
	/// Generate the tweens for the current pair of transforms (currentTransform and nextTransform)
	/// Dequeues the next Transform from the list of transforms.
	/// Also registers all the tweens to check if al lthe tweens are done to create the next tweens
	/// </summary>
	createNextTweens()
	{
		if (this.transforms.length - 1 == this.position)
		{
			if (this.finalCallback != null) this.finalCallback();
			return;
		}
		
		// clear the list of current tweens (maybe wait for completion)
		while (this.currentTweens.length > 0)
		{
			var done = this.currentTweens[0];
			this.currentTweens.splice(0, 1);
			this.tweens.returnObject(done);
		}
		
		this.completeTweenCounter = 0;
		
		// get the next transform
		this.position++;
		var nextTransform = this.transforms[this.position];
		var timeDiff = nextTransform.time - this.currentTransform.time;
		timeDiff *= this.timeFactor;
		
		// Check each thing that could be tweened to see if it will be tweened
		if (nextTransform.x != null && nextTransform.x != this.currentTransform.x)
		{
			var tween = this.tweens.getNextObject();
			tween.init((x) => this.drawable.x = x, Engine.SimpleTween.easeLinear, this.currentTransform.x, nextTransform.x * this.moveFactor, timeDiff);
			tween.onFinish = () => this.checkAllTweensComplete();
			this.currentTweens.push(tween);
		}
		
		if (nextTransform.y != null && nextTransform.y != this.currentTransform.y)
		{
			var tween = this.tweens.getNextObject();
			tween.init((y) => this.drawable.y = y, Engine.SimpleTween.easeLinear, this.currentTransform.y, nextTransform.y * this.moveFactor, timeDiff);
			tween.onFinish = () => this.checkAllTweensComplete();
			this.currentTweens.push(tween);
		}
		
		if (nextTransform.scaleX != null && nextTransform.scaleX != this.currentTransform.scaleX)
		{
			var tween = this.tweens.getNextObject();
			tween.init((scaleX) => this.drawable.scale.x = scaleX, Engine.SimpleTween.easeLinear, this.currentTransform.scaleX, nextTransform.scaleX, timeDiff);
			tween.onFinish = () => this.checkAllTweensComplete();
			this.currentTweens.push(tween);
		}
		
		if (nextTransform.scaleY != null && nextTransform.scaleY != this.currentTransform.scaleY)
		{
			var tween = this.tweens.getNextObject();
			tween.init((scaleY) => this.drawable.scale.y = scaleY, Engine.SimpleTween.easeLinear, this.currentTransform.scaleY, nextTransform.scaleY, timeDiff);
			tween.onFinish = () => this.checkAllTweensComplete();
			this.currentTweens.push(tween);
		}
		
		if (nextTransform.rotation != null && nextTransform.rotation != this.currentTransform.rotation)
		{
			var tween = this.tweens.getNextObject();
			tween.init((rotation) => this.drawable.rotation = rotation, Engine.SimpleTween.easeLinear, this.currentTransform.rotation, nextTransform.rotation, timeDiff);
			tween.onFinish = () => this.checkAllTweensComplete();
			this.currentTweens.push(tween);
		}
		
		// Set currnet to next now that calculation is done
		this.currentTransform = nextTransform;
	}

	goToEnd(drawable /*IAnimationActor*/, transforms /*List<Transform>*/)
	{
		this.drawable = drawable;
		this.transforms = transforms;
		if (transforms.length > 0)
		{
			this.applyTransform(transforms[transforms.length - 1]);
		}
	}

	checkAllTweensComplete()
	{
		this.completeTweenCounter++;
		if (this.completeTweenCounter >= this.currentTweens.length)
		{
			this.createNextTweens();
		}
	}
}

Engine.MultiTransformTweener.Transform = class
{
	constructor(time /*float*/, x /*float?*/, y /*float?*/, scaleX /*float?*/, scaleY /*float?*/, rotation /*float?*/)
	{
		this.x = x != undefined ? x : 1/30;
		this.y = y != undefined ? y : null;
		this.scaleX = scaleX != undefined ? scaleX : null;
		this.scaleY = scaleY != undefined ? scaleY : null;
		this.rotation = rotation != undefined ? rotation : null;
		
		this.time = time;
	}
}