//*******************************************************************************************************
//                                         HOW TO CREATE A TWEEN
//*******************************************************************************************************
//		new Tween (elem, property, prefix, suffix, startTween, endTween, effect, duration, callBack);
//
//
//*******************************************************************************************************
//                                    HOW TO KNOW PROGRESS OF A TWEEN
//*******************************************************************************************************
//		var myTween = new Tween (elem, property, prefix, suffix, startTween, endTween, effect, duration, callBack);
//		var progression = myTeen.getProgress();
//
//		See docs of getProgress() function a line 110 for more information
//*******************************************************************************************************





//=============================================================
//Initialisation des variables
//=============================================================
var TweensReferences = new Array();	//Array containing references of each current Tweens



//=============================================================
//Fonction De lancement d'un tweening (constructeur)
//=============================================================
// Function to start a tween (constructor)
//	@elem				{HTMLElement}	:		ID de l'objet à modifier																	|			Object's ID to modify
//	@property		{String}			:		Propriété de l'objet à modifier														|			Property to modify
//	@prefix			{String}			:		Chaîne à ajouter avant la valeur													|			Prefix to add before the value
//	@suffix			{String}			:		Chaîne à ajouter après la valeur (l'unitée par exemple)		|			suffix to add after the value (unity for exemple)
//	@startTween	{Number}			:		Valeur de départ de la propriété													|			Start value of the Tween
//	@endTween		{Number}			:		Valeur de fin de la propriété															|			End value of the Tween
//	@effect			{String}			:		Effet à effectuer																					|			Effect to do
//	@duration		{Number}			:		Durée de l'effet en millisecondes													|			Duration of the effect
//	@callBack		{Function}		:		Fonction appelée lors de la fin du tweening								|			Function to call at the end of the Tween
//
//	Returns a Reference to the tween
//=============================================================
Tween = function (elem, property, prefix, suffix, startTween, endTween, effect, duration, callBack) {

	//Teste de l'existance de la fonction de tweening demandée dans "effect"
	//Si la fonction n'existe pas on affiche uun message d'erreur contenant diverses informations
	try{
		eval(effect);
	}
	catch(err){
		if(elem.id != undefined)
			var e = " d'identifiant <b>"+elem.id+"</b>";
		else if(elem.name != undefined)
			var e = " de nom <b>"+elem.name+"</b>";

		var s = "z-index: 100000; position: absolute; font-size:14px; color:#CC0000; border-width: 1px; border-style: dashed; border-color: #CC0000;";
		var m = "&nbsp;&nbsp;&nbsp;- La fonction <b><i>"+effect+"</i></b> déclarée sur l'élément <b>"+elem.tagName+"</b>"+e+" n'existe pas."
		if(!document.getElementById('errorReport'))
			document.body.innerHTML += "<div id='errorReport' style='"+s+"'><b style='font-size: 18px;'>ERREUR :</b><br />"+m+"</div>";
		else
			document.getElementById('errorReport').innerHTML += "<br />"+m;
		return;
	}

	//Initialisation de  la propriété de l'objet
	eval("elem."+property+"='"+prefix+startTween+suffix+"'");

	this.elem						=	elem;
	this.property					=	property;
	this.prefix					=	prefix;
	this.suffix					=	suffix;
	this.startTween				=	startTween;
	this.endTween					=	endTween;
	this.effect					=	effect;
	this.duration					=	duration;
	this.callBack					=	callBack;
	this.stopTime					=	0;
	//Récupération du TIMESTAMP de départ
	var date							=		new Date();
	this.startTimeTween		=		date.getTime();

	//Suppression de la tween identique à la nouvelle si existante
	this.clearTween();

	//Création de l'intervalle
	var Obj = this;
	this.interTween = setInterval(function () {Obj.changeProperty();}, 25);
	TweensReferences.push(new Array(this.interTween, this.property, this.elem));
	return this;
}



//=============================================================
//Fonction retournant le temps écoulé
//=============================================================
// Removes conflict between tweens or a specific tween
Tween.prototype.clearTween = function (specific){
	specific = (specific == undefined)? false : specific;
	for(var i in TweensReferences){
		if(TweensReferences[i][1] == this.property && TweensReferences[i][2] == this.elem && ( (specific && TweensReferences[i][0] == this.interTween) || !specific) ){
			clearInterval(TweensReferences[i][0]);
			TweensReferences.splice(i, 1);
		}
	}
}



//=============================================================
//Fonction retournant le temps écoulé
//=============================================================
// Return time past for a tween
Tween.prototype.getTimeAct = function () {
	var timeAct	=	new Date();
	return timeAct.getTime()-this.startTimeTween;
}



//=============================================================
//Fonction Stoppant une tween
//=============================================================
// Stop a tween
Tween.prototype.stopTween = function () {
	clearInterval(this.interTween);
	var timeAct	=	new Date();
	if(this.stopTime == 0)
		this.stopTime = timeAct.getTime()-this.startTimeTween;
	this.clearTween(true);
}



//=============================================================
//Fonction retournant la progression de la tween
//=============================================================
// Function that returns progression of a Tween
//
// Return an object with thoses properties :
//  @currentState	{Number}	:	Current value of the Tween
//  @startState		{Number} 	:	Value of the start of the Tween
//  @endState			{Number}	:	Value of the end of the Tween
//  @property			{String}	:	Property modified by the Tween
//	@finished			{Boolean}	:	Tween is finished (true) or not (false)
Tween.prototype.getProgress = function () {
	var	res = new Object();
			if(this.stopTime == 0)
				var val			=		eval(this.effect+"("+this.getTimeAct()+", "+this.startTween+", "+(this.endTween-this.startTween)+", "+this.duration+")");
			else
				var val			=		eval(this.effect+"("+this.stopTime+", "+this.startTween+", "+(this.endTween-this.startTween)+", "+this.duration+")");
			res.currentState		=		(this.getTimeAct()>=this.duration && this.stopTime == 0)? this.endTween : val;
			res.startState			=		this.startTween;
			res.endState			=		this.endTween;
			res.property			=		this.property;
			res.finished			=		(this.getTimeAct()>=this.duration || this.stopTime > 0)? true : false;
	return res;
}



//=============================================================
//Fonction effectuant les modification de la propriété de l'objet voulu
//=============================================================
Tween.prototype.changeProperty = function (){
	//Récupération de la valeur courante de la propriété
	var pValue		=		eval(this.effect+"("+this.getTimeAct()+", "+this.startTween+", "+(this.endTween-this.startTween)+", "+this.duration+")");

	//Si la valeur ne concerne pas une position et qu'elle arrive à une valeur
	//inférieure à zéro on la met à zéro sinon sous IE ça plante.
	if(this.property != "style.left" && this.property != "style.top" && this.property != "style.right" && this.property != "style.bottom")
		pValue = (pValue<0)? 0: pValue;

	//Modification de la propriété
	eval("this.elem."+this.property+" = '"+this.prefix+pValue+this.suffix+"'");

	//Fin de la tween
	if(this.getTimeAct()>=this.duration){
		eval("this.elem."+this.property+" = '"+this.prefix+this.endTween+this.suffix+"'");
		this.clearTween(true);
		clearInterval(this.interTween);
		//Appel de la fonction de callback si existante
		if(this.callBack != undefined)
			this.callBack(this.elem, this.property, this.prefix, this.suffix, this.startTween, this.endTween, this.effect, this.duration);
	}
}



//##############################################################################
//##############################################################################
//#################### DECLARATION DES FONCTIONS DE TWEENING ###################
//##############################################################################
//##############################################################################
//                      (fonction reprises depuis flash 8)


//=============================================================
//Tweening linéaire
//=============================================================
function linear (t, b, c, d) {
	return c*t/d + b;
}


//=============================================================
//Tweening d'accélération/décélération
//=============================================================
function easeIn_strong (t, b, c, d) {
	return c*(t/=d)*t*t*t*t + b;
}
function easeOut_strong (t, b, c, d) {
	return c*((t=t/d-1)*t*t*t*t + 1) + b;
}
function easeInOut_strong (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;
}


//=============================================================
//Tweening d'élasticité
//=============================================================
function easeInOut_elastic (t, b, c, d, a, p) {
	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; 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;
}
function easeOut_elastic (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);
}
function easeIn_elastic (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;
}


//=============================================================
//Tweening de rebonds
//=============================================================
function easeOut_bounce (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;
	}
}
function easeIn_bounce (t, b, c, d) {
	return c - easeOut_bounce(d-t, 0, c, d) + b;
}
function easeInOut_bounce (t, b, c, d) {
	if (t < d/2) return easeIn_bounce(t*2, 0, c, d) * .5 + b;
	else return easeOut_bounce(t*2-d, 0, c, d) * .5 + c*.5 + b;
}


//=============================================================
//Tweening de retour arrière
//=============================================================
function easeIn_back (t, b, c, d, s) {
	if (s == undefined) s = 1.70158;
	return c*(t/=d)*t*((s+1)*t - s) + b;
}
function easeOut_back (t, b, c, d, s) {
	if (s == undefined) s = 1.70158;
	return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
}
function easeInOut_back (t, b, c, d, s) {
	if (s == undefined) 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;
}


//=============================================================
//Tweening de rebonds
//=============================================================
function easeIn_regular (t, b, c, d) {
	return c*(t/=d)*t + b;
}
function easeOut_regular (t, b, c, d) {
	return -c *(t/=d)*(t-2) + b;
}
function easeInOut_regular (t, b, c, d) {
	if ((t/=d/2) < 1) return c/2*t*t + b;
	return -c/2 * ((--t)*(t-2) - 1) + b;
}