/*
	FILENAME: jsweld.animation.js
	AUTHOR: Philip Siedow-Thompson (psiedow@co.weld.co.us)
	WRITTEN: 4/2/2009
	REVISIONS: none
	DEPENDENCIES: prototype.js v.1.6.0 (DO NOT USE ANY OTHER VERSION UNTIL TESTED!)
*/

var jsweld;
	jsweld = (jsweld)?jsweld:{};
	jsweld.animation = {};

	/*------------------------------------------------------------------------------------
		DEFINE INTERPOLATION FUNCTIONS - these are used by the animation class to interpolate
											between the start and end values.
	--------------------------------------------------------------------------------------*/
	jsweld.animation.interpolate = {};
		
		/* 
			FUNCTION: linear
			DESCRIPTION: a linear interpolation function.
			ARGUMENTS: 	a_start:number - starting value
						a_delta:number - total change (end-start)
						a_step:number - current step/time
						a_duration:number - total steps/time
		*/
		jsweld.animation.interpolate.linear = function(a_start,a_delta,a_step,a_duration)
			{
				return (a_delta * (a_step/a_duration)) + a_start;		
			}
			
		/* 
			FUNCTION: exponential
			DESCRIPTION: an exponential interpolation function.
			ARGUMENTS: 	a_start:number - starting value
						a_delta:number - total change (end-start)
						a_step:number - current step/time
						a_duration:number - total steps/time
		*/
		jsweld.animation.interpolate.exponential = function(a_start,a_delta,a_step,a_duration)
			{
				return (a_step>=a_duration)?a_start + a_delta: a_delta * 1.001 * (-Math.pow(2, -10 * a_step/a_duration) + 1) + a_start;
			}
		
		/* 
			FUNCTION: exponential
			DESCRIPTION: an rough exponential interpolation function.
			ARGUMENTS: 	a_start:number - starting value
						a_delta:number - total change (end-start)
						a_step:number - current step/time
						a_duration:number - total steps/time
		*/
		jsweld.animation.interpolate.roughExponential = function(a_start,a_delta,a_step,a_duration)
			{
				return ((a_step*1.25)>=a_duration)?a_start + a_delta: a_delta * 1.001 * (-Math.pow(2, -10 * a_step/a_duration) + 1) + a_start;
			}
		
	/*------------------------------------------------------------------------------------
		JSWELD.ANIMATION.ANIMATE - an animation function (interpolates between points and set the
							appropriate styles on each frame.
	--------------------------------------------------------------------------------------*/	
	jsweld.animation.animate = Class.create(
	{
		
		/* 
			FUNCTION: constructor
			DESCRIPTION: initializes a animation object for a node.
			ARGUMENTS:	a_node:node - the block displayed node to animate.
						a_interp:function - one of the interpolation functions.
						a_framesPerSec - the frame rate of the animation function in frames/sec.
		*/
			initialize: function(a_node,a_interp,a_framesPerSec)
			{
				this.onFinishedCallback = null;
				this.timer = null;
				this.startVals = null;
				this.deltaVals = null;
				this.length = 0;
				this.firstFrameTime = 0;
				this.frameRate = (a_framesPerSec && a_framesPerSec>0 && a_framesPerSec<1000)?Math.ceil(1000/a_framesPerSec):16;
				this.interp = (a_interp)?a_interp:jsweldMenu.interpolate.linear;
				this.node = $(a_node);
					if(!this.node)throw new Error('The node passed to jsweldMenu.animate is not valid.');
			},
			
		/* 
			FUNCTION: isAnimating
			DESCRIPTION: Indicates whether the object is currently animating.
			ARGUMENTS: none
			RETURNS: boolean
		*/
			isAnimating: function()
			{
				return (this.timer!=null);
			},
			
		/* 
			FUNCTION: onFrame
			DESCRIPTION: PRIVATEish - called on each frame, performs the lerp and sets the styles for the node.
			ARGUMENTS: none
			RETURNS: none
		*/
			onFrame: function()
			{
				var cTime = new Date().getTime();
				var tDelta = cTime-this.firstFrameTime;
			
				for(var key in this.startVals)
				{
					var simp = {};
						if(key!='opacity')simp[key] = Math.ceil(this.interp(this.startVals[key],this.deltaVals[key],tDelta,this.length)) + 'px';
						else simp[key] = this.interp(this.startVals[key],this.deltaVals[key],tDelta,this.length);
					
					this.node.setStyle(simp);
				}
				
				if(tDelta>=this.length)
				{
					window.clearInterval(this.timer);
					this.timer = null;
					if(this.onFinishedCallback)this.onFinishedCallback(this.node);
				}
			},
			
		/* 
			FUNCTION: animate
			DESCRIPTION: Call to initiate an animation.
			ARGUMENTS:	a_start:object - an object containing starting key-value pairs.
						a_end:object - an object containing starting key-value pairs.
						a_sec:number - the duration of the animation
						a_callback:function - a function called when the animation is complete (OPTIONAL)
			RETURNS: none
		*/
			animate: function(a_start,a_end,a_sec,a_callback)
			{
				var thisRef = this;
				this.onFinishedCallback = a_callback;
				
				this.firstFrameTime = new Date().getTime();
				this.length = (a_sec>0)?1000 * a_sec:0;
				this.startVals = {};
				this.deltaVals = {};
				for(var key in a_start)
				{
					if(a_end[key]!=undefined)
					{
						this.startVals[key] = a_start[key];
						this.deltaVals[key] = a_end[key]-a_start[key];
					}
				}
				
				this.onFrame();
				this.timer = window.setInterval(function(){thisRef.onFrame();},this.frameRate);
			}						
	});
