var Animate = new function() {
	var hideElement = function(el) {
		el.style.display = "block";
		var h = el.clientHeight;
		el.style.height = '0px';
		
		var tween = this.Tween(el.style,'height','regularEaseIn',0,h,0.4,'px');
		tween.onMotionFinished = function() { el.style.height = 'auto'; }
	}
	
	var showElement = function(el) {
		var h = el.clientHeight;
		var tween = this.Tween(el.style,'height','regularEaseOut',h,0,0.4,'px');
		tween.onMotionFinished = function() { el.style.display = 'none'; }		
	}
	
	var tween = function(obj,prop,func,begin,finish,duration,suffix,prefix) {
		func = Animate[func];
		
		var this_tween = this;
		var starting_time = (new Date()).getTime();
		var ending_time = starting_time + (duration * 1000);
		var current_update;
	
		this.update = function() {
			var now = new Date().getTime();
			var t = (now - starting_time) / 1000;
			var new_pos = func(t,begin,finish-begin,duration);
			
			obj[prop] = prefix + new_pos + suffix;
			
			if (now <= ending_time) {
				current_update = window.setTimeout(this_tween.update,0);
			} else {
				obj[prop] = prefix + finish + suffix;
				if (this_tween.onMotionFinished) this_tween.onMotionFinished();
				cancel();
				return true;
			}
		}
		
		var cancel = function() {
			if (current_update) window.clearTimeout(current_update);
			obj.tweens[prop] = false;
		}
		
		this.cancel = cancel;
	}
	
	this.Tween = function(obj,prop,func,begin,finish,duration,suffix,prefix) {
		if (!arguments.length || !obj) return;
		if (!suffix) suffix = '';
		if (!prefix) prefix = '';
		
		// if a tween affecting the same property on the same object 
		// is already going on, then cancel that one and set the beginning
		// of this one to the current valye of the previous
		if (obj.tweens && obj.tweens[prop]) {
			obj.tweens[prop].cancel();
			begin = parseFloat(obj[prop]);
		}
		
		var t = new tween(obj,prop,func,begin,finish,duration,suffix,prefix);
		if (!obj.tweens) obj.tweens = [];
		obj.tweens[prop] = t;
		t.update();
		
		return t;
	}
	
	this.backEaseIn = function(t,b,c,d,a,p) {
		if (s == undefined) var s = 1.70158;
		return c * (t /= d) * t * ((s + 1) * t - s) + b;
	}
	
	this.backEaseOut = function(t,b,c,d,a,p) {
		if (s == undefined) var s = 1.70158;
		return c * ((t = t/d -1) * t * ((s + 1) * t + s) + 1) + b;
	}
	
	this.backEaseInOut = function(t,b,c,d,a,p) {
		if (s == undefined) var s = 1.70158; 
		if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
		return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
	}
	
	this.elasticEaseIn = function(t,b,c,d,a,p) {
		if (t==0) return b;  
		if ((t/=d)==1) return b + c;  
		if (!p) p = d * .3;
		
		if (!a || a < Math.abs(c)) {
			a = c; var s = p / 4;
		} else {
			var s = p / (2 * Math.PI) * Math.asin(c / a);
		}
		
		return - (a * Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
	}
	
	this.elasticEaseOut = function (t,b,c,d,a,p) {
		if (t==0) return b; 
		if ((t/=d)==1) return b+c; 
		if (!p) p=d*.3;
		
		if (!a || a < Math.abs(c)) { 
			a=c; var s=p/4;
		} else {
			var s = p/(2*Math.PI) * Math.asin (c/a);
		}
		
		return (a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b);
	}
	
	this.elasticEaseInOut = function (t,b,c,d,a,p) {
		if (t==0) return b; 
		if ((t/=d/2)==2) return b+c;
		if (!p) var p=d*(.3*1.5);
		
		if (!a || a < Math.abs(c)) {
			var a=c; var s=p/4;
		} else {
			var s = p/(2*Math.PI) * Math.asin (c/a);
		}
		
		if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
		
		return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
	}
	
	this.bounceEaseOut = function(t,b,c,d) {
		if ((t/=d) < (1/2.75)) {
			return c*(7.5625*t*t) + b;
		} else if (t < (2/2.75)) {
			return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
		} else if (t < (2.5/2.75)) {
			return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
		} else {
			return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
		}
	}
	
	this.bounceEaseIn = function(t,b,c,d) {
		return c - this.bounceEaseOut (d-t, 0, c, d) + b;
	}
	
	this.bounceEaseInOut = function(t,b,c,d) {
		if (t < d/2) return this.bounceEaseIn (t*2, 0, c, d) * .5 + b;
		else return this.bounceEaseOut (t*2-d, 0, c, d) * .5 + c*.5 + b;
	}
	
	this.strongEaseInOut = function(t,b,c,d) {
		return c*(t/=d)*t*t*t*t + b;
	}
	
	this.regularEaseIn = function(t,b,c,d) {
		return c*(t/=d)*t + b;
	}
	
	this.regularEaseOut = function(t,b,c,d) {
		return -c *(t/=d)*(t-2) + b;
	}
	
	this.regularEaseInOut = function(t,b,c,d) {
		if ((t/=d/2) < 1) return c/2*t*t + b;
		return -c/2 * ((--t)*(t-2) - 1) + b;
	}
	
	this.strongEaseIn = function(t,b,c,d) {
		return c*(t/=d)*t*t*t*t + b;
	}
	
	this.strongEaseOut = function(t,b,c,d) {
		return c*((t=t/d-1)*t*t*t*t + 1) + b;
	}
	
	this.strongEaseInOut = function(t,b,c,d) {
		if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
		return c/2*((t-=2)*t*t*t*t + 2) + b;
	}
}