/**
	@fileOverview Contains the coweldco.animate namespace
	@author Philip Siedow-Thompson
	@version $Id$
*/

var coweldco;
	coweldco = (coweldco) ? coweldco : {};
	
(function() {
	
	/**
		@namespace Contains classes, constants and functions used for animating DOM nodes
	*/
	coweldco.animate = (coweldco.animate) ? coweldco.animate : {};
	
	/**
		Calculates a linear interpolation between two numbers.
		@param {Number} start The Starting value.
		@param {Number} delta The amount to change over the interpolation.
		start + delta = endValue. Converselty, end- star = delta.
		@param {Number} step the current step/time
		@param {Number} duration the total steps/time
	*/
	coweldco.animate.linearInterpolation = function(start, delta, step, duration) {
		return (delta * (step/duration)) + start;
	}
	
	/**
		Calculates a exponential interpolation between two numbers.
		@param {Number} start The Starting value.
		@param {Number} delta The amount to change over the interpolation.
		start + delta = endValue. Converselty, end- star = delta.
		@param {Number} step the current step/time
		@param {Number} duration the total steps/time
	*/
	coweldco.animate.exponentialInterpolation = function(start, delta, step, duration) {
		return (step>=duration)?start + delta: delta * 1.001 * (-Math.pow(2, -10 * step/duration) + 1) + start;
	}
	
	/**
		Constructs a new Animator bound to a node.
		
		@class Animates a node between two sets of numeric css styles using
		and interpolation function. The Animator will operate on any css
		style that uses pixel values or on the opacity value.
		@param {Node} node The DOM node to animate.
		@param {Function} interp The interpolation function to use in the animation.
		@param {Number} framesPerSec the frame rate of the interpolation (in lerps per second)
	*/
	coweldco.animate.Animator = function(node, interp, framesPerSec) {
		this.timer = null;
		this.startVals = null;
		this.deltaVals = null;
		this.length = 0;
		this.firstFrameTime = 0;
		
		this.frameRate = (framesPerSec 
				&& framesPerSec>0 
				&& framesPerSec<1000)
			? Math.ceil(1000/framesPerSec)
			: 16;
		
		this.interp = (interp)
			? interp
			: weldMenu.interpolate.linear;
			
		this.node = $(node);
		if(!this.node) {
			throw new Error('The node passed to coweldco.animate.Animator is not valid.');
		}
	}
	
	/**
		Determines if the animator is animating
		@memberOf coweldco.animate.Animator.prototype
		@returns {Boolean} true if it is animating, otherwise false
	*/
	coweldco.animate.Animator.prototype.isAnimating = function() {
		return (this.timer!=null);
	}
	
	/**
		Stops the Animator.
		@memberOf coweldco.animate.Animator.prototype
	*/
	coweldco.animate.Animator.prototype.stop = function() {
		if(this.timer!=null) {
			window.clearInterval(this.timer);
			this.timer = null;
		}
	}
	
	/**
		Called on every frame to run the interpolation
		@private
		@memberOf coweldco.animate.Animator.prototype
	*/
	coweldco.animate.Animator.prototype.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) {
			this.stop();
		}
	}
	
	/* 
		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
		RETURNS: none
	*/
	/**
		Starts an animation.
		@memberOf coweldco.animate.Animator.prototype
		@param {Object} start an object containing starting values (as Numbers without units!)
		@param {Object} end an object containing ending values (as Numbers without units!)
		@param {Number} sec the duration of the animation in Seconds.
	*/
	coweldco.animate.Animator.prototype.animate = function(start, end, sec) {
		this.firstFrameTime = new Date().getTime();
		this.length = (sec>0) ? 1000 * sec : 0;
		this.startVals = {};
		this.deltaVals = {};
		
		for(var key in start) {
			if(end[key]) {
				this.startVals[key] = start[key];
				this.deltaVals[key] = end[key]-start[key];
			}
		}
		
		this.onFrame();
		this.timer = window.setInterval(this.onFrame.bind(this), this.frameRate);
	}
	
})();
