/**
 * http://www.minuit4.fr/
 * 
 * @author Arnaud NICOLAS - arno06@gmail.com
 * 
 * Copyright the original author or authors.
 *
 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.mozilla.org/MPL/MPL-1.1.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
function M4Tween()
{
	this.next = null;
	this.nextInPool = null;
}

M4Tween.prototype.configure = function (pId, pFirstInfos, pStartTime, pDuration, pMaxTime, pEase, pOnComplete)
{
	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.occurences = {};
M4Tween.create = function(pId, pTime, pProperty, pOnComplete)
{
	if(M4Tween.occurences[pId])
		M4Tween.killTweenOf(pId);
	var startTime = new Date().getTime() * 1;
	var ease = Linear.easeNone;
	var durationTime = pTime;
	var maxTime = (startTime*.001)+durationTime;
	var values = [];
	var init = false;
	var firstInfos;
	var tmp, s, p;
	var templateValue;
	var type;
	var property;
	var startValue;
	var distanceValue;
	var element = document.getElementById(pId);
	var css = document&&document.defaultView&&document.defaultView.getComputedStyle?document.defaultView.getComputedStyle(element, null):element.style;
	for(var i in pProperty)
	{
		type= "";
		property = i;
		s = pProperty[i]+"";
		p = s.search(/(px|\%)/);
		if(p!=-1)
			type = s.substr(p);
		pProperty[i] = s.replace(/(px|\%)/,"");
		switch(i)
		{
			case "ease":
				ease = pProperty[i];
				continue;
			break;
			case "rotation":
				if(Prototype.Browser.Opera||Prototype.Browser.IE)
					continue;
				/*MozTransform:rotate(0deg) - WebkitTransform:rotate(0deg)*/
				type = "deg";
				templateValue = new Template("rotate(#{value})");
				pProperty[i] = pProperty[i].replace(/(deg)/,"");
				property =document.getElementById(pId).style.MozTransform!=undefined?"MozTransform":"WebkitTransform";
				startValue = document.getElementById(pId).style[property].replace(/rotate\(/,"");
				startValue = startValue.replace(/deg\)/,"");
			break;
			case "opacity":
				if(Prototype.Browser.IE)
				{
					/*filter : alpha(opacity=0);*/
					templateValue = new Template("alpha(opacity=#{value})");
					pProperty[i] *= 100;
					property = "filter";
					startValue = element.style[property].replace(/alpha\(opacity\=/,"");
					startValue = startValue.replace(/\)/,"");
				}
				else
					startValue = element.getStyle("opacity");
			break;
			default:
				startValue = css[i].replace(/(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;
	}
	
	M4Tween.initPool();
	var instance = M4Tween.current;
	M4Tween.current = instance.nextInPool;
	M4Tween.available--;
	instance.configure(pId, firstInfos, startTime, durationTime, maxTime, ease, pOnComplete);
	
	M4Tween.occurences[pId] = instance;
	var timer;
	instance.enterFrame = setInterval(function ()
	{
		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;
		var e = document.getElementById(instance.id);
		if(!e)
		{
			instance.enterFrame = null;
			return false;
		}
		while(infos)
		{
			var valeur = (infos.startValue + ( factor * infos.distanceValue))+""+infos.type;
			e.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();}
		}
	}, 20);
}
M4Tween.killTweenOf = function (pId)
{
	if(M4Tween.occurences[pId].enterFrame)
	{
		clearInterval(M4Tween.occurences[pId].enterFrame);
		M4Tween.occurences[pId].enterFrame = null;
	}
	M4Tween.occurences[pId].nextInPool = M4Tween.current;
	M4Tween.current = M4Tween.occurences[pId];
	M4Tween.available++;
	M4Tween.occurences[pId] = null;
	delete(M4Tween.occurences[pId]);
}

M4Tween.GROWTH_RATE = 10;
M4Tween.available = 0;
M4Tween.current;

M4Tween.initPool = function (pNumber)
{
	if(M4Tween.available>0)
		return;
	if(!pNumber)
		pNumber = M4Tween.GROWTH_RATE;	
	var pooled;
	var i = pNumber+1;
	while(--i)
	{
		pooled = new M4Tween();
		pooled.nextInPool = M4Tween.current;
		M4Tween.current = pooled;
	}
	M4Tween.available = pNumber;
}

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;}
