/*
 * Javascript Time Based Animation
 * Description: Animate any style property of any object to any value
 * Functionality: CORE/Interface
 * Author: Stephen Holdaway
 * 
 * Originally created: 25/04/2011
 * Updated (v2): 11/07/2011 - Added namespace and dynamic property setting.
 * 
 * Use: a.a([target_element], [attribute], [target_value], [duration (ms)], [[mode]]){
 * 
 * Notes:
 * Mode defaults to 'set' but also supports 'toggle'. Toggle mode is currently buggy as of v2.
 */

var a = {
	
	//Private vars
	_anim: new Array(),
	_atmr: new Array(),
	_timer: null,
	
	//Frame driver
	_dr: function(){
		for(var key in a._anim){
			a._anim[key].an(key);
		}
	},
	
	//Parse string into value and unit
	p: function(v){
		cv =  parseFloat(v);
		if(cv=='NaN') cv = 0;
		unt = '';
		var validChars = "0123456789.";
		for (i = 0,c=v.length;i<c;i++) {
			if (validChars.indexOf(v.charAt(i)) == -1) { 
				if (i > 0) {
					unt = v.substring(i-1);
				}
			}
		}
		return {v:cv,u:unt};
	},
	
	//Animation object
	_obj: function(){
		mode = 'set';	//Operation mode
		ease = null;	//Easing
		start = null;	//Start microtime
		target = null;	//target element
		tval = null;	//target value
		dur = null;		//Milliseconds
		attr = null;	//CSS style attribute
		unt = null;		//style unit (px,%,em, etc)
		stval = null;	//starting value (before animation)
		pclk = null;	//Change per click;
		an = null;		//Place for animation function
		cb = null;		//Place for callback function
		ch = null;		//Actual value change
	},
	
	//Main animation function
	a: function(target_element,target_attribute,target_value,duration,p){		
		//Turn away incomplete/broken calls
		if(target_element==undefined||target_attribute==undefined||target_value==undefined||duration==undefined) return;
		if(p == undefined) p = new Object();
		if(target_element._a == undefined){ target_element._a = new Object(); sc=true;} //set id array and skip check
		if(p.mode==undefined) p.mode = 'set';
		
		//Create animation object
		l = this._anim.length;
		this._anim[l] = new this._obj;
		an = this._anim[l];
		
		//Delete duplicate animations
		for(key in a._anim){
			if(a._anim[key].target===target_element && a._anim[key].attr==target_attribute)
				a._anim.splice(key,1);
		}
		
		an.target = target_element;
		an.attr = target_attribute;
		u = a.p(target_value);
		if(an.attr!='opacity' && u.u=='')
			u.u = 'px';
		an.tval = u.v;
		an.unt = u.u;
		an.dur = duration;
		p.ease!=undefined ? an.ease = p.ease : an.ease = 0.9;
		an.mode = p.mode;
		an.start = new Date().getTime();
		(p.callback != undefined) ? an.cb = p.callback : an.cb = null;
		
		//Sort out starting value
		comp = an.target.currentStyle || getComputedStyle(an.target, null);
		u = a.p(comp[an.attr]);
		if(u.u != an.unt){
			//convert units here
		} else {
			an.stval = u.v;
		}
		
		//Cancel if no change
		if(an.stval==an.tval){ a._anim.splice(l,1);return};
		
		//Extra Modes
		if(p.mode=='toggle'){
			if(!an.stval == 0)
				an.tval = 0;
			else g.st(an.target,{display:'block'});
		}
	
		//Set change amount
		an.ch = an.tval-an.stval;
		
		//Value change per click
		an.pclk = an.tval/an.dur;
		
		//Init timer and create function
		an.an = function(key){
			an = a._anim[key];
			nw = new Date().getTime();
			elp = nw - an.start;
			var del = false;
			if(elp>=an.dur){
				val = an.tval;
				del = true;
			} else {
				t=elp/an.dur;
				val = ( ( Math.pow((1-t),2)*0 + 2*(1-t)*(t*((1-0)*an.ease))+(Math.pow(t,2)*1) ) * (an.ch) ) + an.stval;
				val = Math.round(val*100)/100;
			}
			an.target.style[an.attr] = (val)+an.unt;
			if(del){
				//Run callback
				if(an.cb!=null){
					an.cb();
				}
				if(an.mode=='toggle' && an.stval != 0)
					g.st(an.target,{display:'none'});
				a._anim.splice(key,1);
				if(a._anim.length==0){
					clearInterval(a._timer);
					a._timer=null;
				}
			}
		};
		
		//Start animating!
		if(a._timer==null) a._timer = setInterval(a._dr,1);
	}
};
