
	// ----------------------------------
	// -- JavaScript Animation Library --
	// ----------------------------------
	// -- Author: Stephan Themis
	// -- Copyright THEMIS Web Technologies 2011
	// --------------------------------------
	
	var animation_timelineArray = new Array();
	
	function animation_Timeline(strEndEventCommand)
	{
		this.fps = 50;					// frames per second

		this.currentTime = 0;			// current time is ms
		this.currentFrame = 0;			// current frame count
		this.startTime = 0;			// start time in ms
		this.frameDuration = 0;		// frame duration in ms
		this.timer = null;				// global animation timer
		this.objectCount = 0;			// total number of objects
		this.objects = new Array();	// array of animation timers
		this.endEventCommand = strEndEventCommand;
		
		this.timelineID = animation_timelineArray.length;
		animation_timelineArray[this.timelineID] = this;
		
		this.addTranslation = function(divTarget, transStartTime, transEndTime, startX, startY, endX, endY)
		{
			var objectID = this.objectCount;
			this.objects[objectID] = new animation_Translation(divTarget, transStartTime, transEndTime, startX, startY, endX, endY, objectID);
			this.objectCount++;
		}

		this.addFade = function(divTarget, fadeStartTime, fadeEndTime, startOpacity, endOpacity)
		{
			var objectID = this.objectCount;
			this.objects[objectID] = new animation_Fade(divTarget, fadeStartTime, fadeEndTime, startOpacity, endOpacity, objectID);
			this.objectCount++;
		}
		
		this.addScale = function(divTarget, scaleStartTime, scaleEndTime, startWidth, startHeight, endWidth, endHeight)
		{
			var objectID = this.objectCount;
			this.objects[objectID] = new animation_Scale(divTarget, scaleStartTime, scaleEndTime, startWidth, startHeight, endWidth, endHeight, objectID);
			this.objectCount++;
		}

		this.startClock = function()
		{
			this.frameDuration = Math.round((1/this.fps) * 1000);		// frame duration in ms
		
			clearInterval(this.timer);
			this.startTime = (new Date()).getTime();
			this.timer = setInterval("animation_incrementClock("+this.timelineID+")", this.frameDuration);
		}
	
		this.run = function()
		{
			this.startClock();
			
			for(var i=0; i<this.objectCount; i++)
			{
				if(this.objects[i].type == "Translation")
					this.objects[i].timer = setInterval("animation_updateTranslation("+this.timelineID+", "+i+")", this.frameDuration);
				else if(this.objects[i].type == "Fade")
					this.objects[i].timer = setInterval("animation_updateFade("+this.timelineID+", "+i+")", this.frameDuration);
				else if(this.objects[i].type == "Scale")
					this.objects[i].timer = setInterval("animation_updateScale("+this.timelineID+", "+i+")", this.frameDuration);
			}
		}
	}

	function animation_Translation(divTarget, startTime, endTime, startX, startY, endX, endY, objectID)
	{
		this.targetDiv = divTarget;
		this.startTime = startTime;
		this.endTime = endTime;
		this.startX = startX;
		this.startY = startY;
		this.endX = endX;
		this.endY = endY;
		this.accelerationX = 0.0;
		this.initialVelocityX = 0.0;
		this.accelerationY = 0.0;
		this.initialVelocityY = 0.0;
		this.type = "Translation";
		
		this.timer = null;
		this.objectID = objectID;

		var translationTime = this.endTime - this.startTime;
		
		this.initialVelocityX = 2 * (this.endX-this.startX) / translationTime;
		this.initialVelocityY = 2 * (this.endY-this.startY) / translationTime;
		this.accelerationX = -this.initialVelocityX / translationTime;
		this.accelerationY = -this.initialVelocityY / translationTime;
	}
	
	function animation_Fade(divTarget, startTime, endTime, startOpacity, endOpacity, objectID)
	{
		this.targetDiv = divTarget;
		this.startTime = startTime;
		this.endTime = endTime;
		this.startOpacity = startOpacity;
		this.endOpacity = endOpacity;
		this.acceleration = 0.0;
		this.initialVelocity = 0.0;
		this.type = "Fade";
		
		this.timer = null;
		this.objectID = objectID;

		var fadeTime = this.endTime - this.startTime;
		
		this.initialVelocity = (this.endOpacity - this.startOpacity) / fadeTime;
	}
	
	function animation_Scale(divTarget, startTime, endTime, startWidth, startHeight, endWidth, endHeight, objectID)
	{
		this.targetDiv = divTarget;
		this.startTime = startTime;
		this.endTime = endTime;
		this.startWidth = startWidth;
		this.startHeight = startHeight;
		this.endWidth = endWidth;
		this.endHeight = endHeight;
		this.accelerationX = 0.0;
		this.initialVelocityX = 0.0;
		this.accelerationY = 0.0;
		this.initialVelocityY = 0.0;
		this.type = "Scale";
		
		this.timer = null;
		this.objectID = objectID;

		var translationTime = this.endTime - this.startTime;
		
		this.initialVelocityX = 2 * (this.endWidth-this.startWidth) / translationTime;
		this.initialVelocityY = 2 * (this.endHeight-this.startHeight) / translationTime;
		this.accelerationX = -this.initialVelocityX / translationTime;
		this.accelerationY = -this.initialVelocityY / translationTime;
	}

	function animation_updateTranslation(timelineID, objectID)
	{
		var translationObject = animation_timelineArray[timelineID].objects[objectID];
		
		if(translationObject.endTime <= animation_timelineArray[timelineID].currentTime)
		{
			translationObject.targetDiv.style.left = translationObject.endX+"px";
			translationObject.targetDiv.style.top = translationObject.endY+"px";
			clearInterval(translationObject.timer);
		}
		else if(translationObject.startTime <= animation_timelineArray[timelineID].currentTime)
		{
			var currentX = 0;
			var currentY = 0;
			
			var translationTime = (animation_timelineArray[timelineID].currentTime - translationObject.startTime);		// translation time in seconds
			
			currentX = 0.5 * translationObject.accelerationX * Math.pow(translationTime, 2) + translationObject.initialVelocityX * translationTime + translationObject.startX;
			currentY = 0.5 * translationObject.accelerationY * Math.pow(translationTime, 2) + translationObject.initialVelocityY * translationTime + translationObject.startY;
			
			translationObject.targetDiv.style.left = Math.round(currentX)+"px";
			translationObject.targetDiv.style.top = Math.round(currentY)+"px";
			translationObject.targetDiv.style.display = "block";
		}
	}

	function animation_updateFade(timelineID, objectID)
	{
		var fadeObject = animation_timelineArray[timelineID].objects[objectID];
		
		if(fadeObject.endTime <= animation_timelineArray[timelineID].currentTime)
		{
			fadeObject.targetDiv.style.filter = "alpha(opacity="+fadeObject.endOpacity+")";
			fadeObject.targetDiv.style.opacity = fadeObject.endOpacity/100;
			clearInterval(fadeObject.timer);
		}
		else if(fadeObject.startTime <= animation_timelineArray[timelineID].currentTime)
		{
			var currentOpacity = 0;

			var fadeTime = (animation_timelineArray[timelineID].currentTime - fadeObject.startTime);		// fade time in seconds
			
			currentOpacity = 0.5 * fadeObject.acceleration * Math.pow(fadeTime, 2) + fadeObject.initialVelocity * fadeTime + fadeObject.startOpacity;
			
			fadeObject.targetDiv.style.filter = "alpha(opacity="+currentOpacity+")";
			fadeObject.targetDiv.style.opacity = currentOpacity/100;
			fadeObject.targetDiv.style.display = "block";
		}
	}
	
	function animation_updateScale(timelineID, objectID)
	{
		var scaleObject = animation_timelineArray[timelineID].objects[objectID];
		
		if(scaleObject.endTime <= animation_timelineArray[timelineID].currentTime)
		{
			scaleObject.targetDiv.style.width = scaleObject.endWidth+"px";
			scaleObject.targetDiv.style.height = scaleObject.endHeight+"px";
			clearInterval(scaleObject.timer);
		}
		else if(scaleObject.startTime <= animation_timelineArray[timelineID].currentTime)
		{
			var currentWidth = 0;
			var currentHeight = 0;
			
			var translationTime = (animation_timelineArray[timelineID].currentTime - scaleObject.startTime);		// translation time in seconds
			
			currentWidth = 0.5 * scaleObject.accelerationX * Math.pow(translationTime, 2) + scaleObject.initialVelocityX * translationTime + scaleObject.startWidth;
			currentHeight = 0.5 * scaleObject.accelerationY * Math.pow(translationTime, 2) + scaleObject.initialVelocityY * translationTime + scaleObject.startHeight;

			scaleObject.targetDiv.style.width = Math.round(currentWidth)+"px";
			scaleObject.targetDiv.style.height = Math.round(currentHeight)+"px";
			scaleObject.targetDiv.style.display = "block";
		}
	}

	function animation_incrementClock(timelineID)
	{
		var bufferedTime = (new Date()).getTime();
		animation_timelineArray[timelineID].currentTime = bufferedTime - animation_timelineArray[timelineID].startTime;
		animation_timelineArray[timelineID].currentFrame = Math.round(animation_timelineArray[timelineID].currentTime / animation_timelineArray[timelineID].frameDuration);
		
		for(var i=0; i<animation_timelineArray[timelineID].objectCount; i++)
		{
			if(animation_timelineArray[timelineID].objects[i].endTime >= animation_timelineArray[timelineID].currentTime)
				return;
		}
		
		clearInterval(animation_timelineArray[timelineID].timer);
		
		if(animation_timelineArray[timelineID].endEventCommand != "")
			eval(animation_timelineArray[timelineID].endEventCommand);
	}
		
