/**
 * @author Arnaud NICOLAS - arno06@gmail.com
 */
function M4Tween(pId, pFirstInfos, pStartTime, pDuration, pMaxTime, pEase, pOnComplete)
{
	this.next = null;
	this.prev = null;
	this.id = pId;
	this.firstInfos = pFirstInfos;
	this.startTime = pStartTime;
	this.durationTime = pDuration;
	this.maxTime = pMaxTime;
	this.ease = pEase;
	this.onComplete = pOnComplete;
}
M4Tween.prototype.enterFrame = null;
M4Tween.prototype.render = function (pe)
{
	var timer = new Date().getTime();
	timer = (timer - this.startTime) * .001;
	var t = (timer<this.durationTime);
	var factor = t? this.ease(timer, 0, 1, this.durationTime ):1;
	var infos = this.firstInfos;
	while(infos)
	{
		var valeur = (infos.startValue + ( factor * infos.distanceValue))+""+infos.type;
		document.getElementById(this.id).style[infos.property] = !infos.templateValue?valeur:infos.templateValue.evaluate({value:valeur});
		infos = infos.next;
	}
	if(!t&&M4Tween.occurences[this.id])
	{
		this.enterFrame.stop();
		this.enterFrame = null;
		delete(M4Tween.occurences[this.id]);
		if(this.onComplete){this.onComplete();}
	}
}
M4Tween.occurences = {};
M4Tween.create = function(pId, pTime, pProperty, pOnComplete)
{
	M4Tween.killTweenOf(pId);
	var startTime = new Date().getTime() * 1;
	var ease = Linear.easeNone;
	var durationTime = pTime;
	var maxTime = (startTime*.001)+durationTime;
	var values = new Array();
	var init = false;
	var firstInfos;
	var tmp;
	for(var i in pProperty)
	{
		var templateValue;
		var type = "";
		var property = i;
		var startValue;
		var distanceValue;
		switch(i)
		{
			case "ease":
				ease = pProperty[i];
			break;
			case "rotation":
				if(!Prototype.Browser.Opera)
				{
					type = "deg";
					templateValue = new Template("rotate(#{value})");
					pProperty[i] = pProperty[i].sub(/(deg)/,"");
					property =$(pId).style.MozTransform!=undefined?"MozTransform":"WebkitTransform";
					startValue = $(pId).style[property].sub(/rotate\(/,"");
					startValue = startValue.sub(/deg\)/,"");
				}
			break;
			case "opacity":
				startValue =$(pId).getStyle("opacity");
			break;
			default:
				pProperty[i].scan(/(px|\%)/,function(e){type=e[0];});
				pProperty[i] = pProperty[i].sub(/(px|\%)/,"");
				startValue = $(pId).getStyle(i).sub(/(px|\%)/,"");
			break;
		}
		if(startValue==pProperty[i]||!property)
			continue;
		distanceValue = pProperty[i] - startValue;
		var a = new M4TweenInfos(property, startValue*1, distanceValue*1, type, templateValue);
		if(!init){firstInfos = a;init = true;}
		else{tmp.next = a;}
		tmp = a;
	}
	var instance = new M4Tween(pId, firstInfos, startTime, durationTime, maxTime, ease, pOnComplete);
	M4Tween.occurences[pId] = instance;
	if(!instance.enterFrame)
		instance.enterFrame = new PeriodicalExecuter(function (pe)
		{
			var timer = new Date().getTime();
			timer = (timer - instance.startTime) * .001;
			var t = (timer<instance.durationTime);
			var factor = t? instance.ease(timer, 0, 1, instance.durationTime ):1;
			var infos = instance.firstInfos;
			while(infos)
			{
				var valeur = (infos.startValue + ( factor * infos.distanceValue))+""+infos.type;
				$(instance.id).style[infos.property] = !infos.templateValue?valeur:infos.templateValue.evaluate({value:valeur});
				infos = infos.next;
			}
			if(!t&&M4Tween.occurences[instance.id])
			{
				M4Tween.killTweenOf(instance.id);
				if(instance.onComplete){instance.onComplete();}
			}
		}, .02);
}
M4Tween.killTweenOf = function (pId)
{
	if(!M4Tween.occurences[pId])
		return null;
	if(M4Tween.occurences[pId].enterFrame)
	{
		M4Tween.occurences[pId].enterFrame.stop();
		M4Tween.occurences[pId].enterFrame = null;
	}
	M4Tween.occurences[pId] = null;
	delete(M4Tween.occurences[pId]);
}

function M4TweenInfos(pProperty, pStartValue, pDistanceValue, pType, pTemplateValue)
{
	this.property = pProperty;
	this.startValue = pStartValue;
	this.distanceValue = pDistanceValue;
	this.type = pType;
	this.templateValue = pTemplateValue;
}



/**Easing Equations by Robert Penner (http://www.robertpenner.com/easing/ - BSD License)**/

function Linear(){}
Linear.easeNone = function(t, b, c, d){return (c*t/d) + b;}


function Back(){}
Back.easeIn = function (t, b, c, d, s){if(!s){s=1.70158;}return c*(t/=d)*t*((s+1)*t - s) + b;}
Back.easeOut = function (t, b, c, d, s){if(!s){s=1.70158;}return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;}
Back.easeInOut = function (t, b, c, d, s){if(!s){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;}


function Bounce(){}
Bounce.easeOut = 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;}}
Bounce.easeIn = function(t, b, c, d){return c - Bounce.easeOut(d-t, 0, c, d) + b;}
Bounce.easeInOut = function (t, b, c, d){if (t < d/2) return Bounce.easeIn (t*2, 0, c, d) * .5 + b;else return Bounce.easeOut (t*2-d, 0, c, d) * .5 + c*.5 + b;}


function Quad(){}
Quad.easeIn = function (t, b, c, d) {return c*(t/=d)*t + b;}
Quad.easeOut = function (t, b, c, d){return -c *(t/=d)*(t-2) + b;}
Quad.easeInOut = function (t, b, c, d){if ((t/=d/2) < 1) return c/2*t*t + b;return -c/2 * ((--t)*(t-2) - 1) + b;}


function Circ(){}
Circ.easeIn = function (t, b, c, d){return ((-c * (Math.sqrt(1 - (t/=d)*t) - 1)) + b);}
Circ.easeOut = function (t, b, c, d) {return ((c * Math.sqrt(1 - (t=t/d-1)*t)) + b);}
Circ.easeInOut = function (t, b, c, d){if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;}

function Elastic(){}
Elastic.easeOut = function (t, b, c, d, a, p) {var s;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; s = p/4; }else s = p/(Math.PI*2) * Math.asin (c/a);return (a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(Math.PI*2)/p ) + c + b);}
Elastic.easeInOut = function (t, b, c, d, a, p){var s;if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5); if (!a || a < Math.abs(c)) { a=c; s = p/4; }else s = p/(Math.PI*2) * Math.asin (c/a); if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(Math.PI*2)/p )) + b; return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(Math.PI*2)/p )*.5 + c + b;}
Elastic.easeIn = function (t, b, c, d, a, p){var s;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; s = p/4; }else s = p/(Math.PI*2) * Math.asin (c/a);return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(Math.PI*2)/p )) + b;}
