/**
 * fade
 * =============================================================================
 * permet d'effectuer une animation d'opacité sur un élément HTML
 * 
 * @author      Erwan Lefèvre <erwan.lefevre@aposte.net>
 * @copyright   Erwan Lefèvre 2009
 * @license     Creative Commons - Paternité 2.0 France - http://creativecommons.org/licenses/by/2.0/fr/
 * @version     2.0
 * @see			http://www.webbricks.org/bricks/fade/
 *
 * @compatible	au 19 janvier 2009, compatibilité assurée pour :
 *				Firefox 1.5+, Internet Explorer 6+, Opéra 10, Safari 3.2.3. 
 *				Autres versions et navigateurs non testés
 */



/*
 * exemple d'utilisation :
 * 

// le minimum :
// fait disparaître une élément html
fade(document.getElementById('truc'),0); 


// plus complet :
// fait apparaître à demi un élément html, en une seconde, à 20 images par seconde, et affiche un message une fois l'animation terminée
fade(
	document.getElementById('truc'),
	0.5,
	0,
	{
		duration : 1000,
		frameRate : 20,
		onFinish : function () { alert('fini !'); }
	}
);

 *
 *
 */







/**
 * setOpacity
 * =============================================================================
 * règle l'opacité d'un élément
 *
 * @param       elem            {element}       l'élément à traiter
 * @param       value           {float}         valeur souhaitée (0=transparent, 1=opaque)
 * @return      string
 *
 */
function setOpacity(elem, value) {
	value = (value == 1)?0.99999:value;

	elem.style.opacity = value;
	elem.style.filter = 'alpha(opacity=' + value*100 + ')';
	elem.style.MozOpacity = value;
	elem.style.KhtmlOpacity = value;
    elem.style.display = "";
}











/**
 * fade()
 * =============================================================================
 * permet d'effectuer une animation d'opacité sur un élément HTML
 *
 * @requires	setOpacity
 *
 * @param		{HTMLelement}	elem			l'élément HTML à animer
 * @param		{float}			to				l'opacité finale (0=transparent, 1=opaque)
 * @param		{float}			from			l'opacité initiale
 * @param		{integer}		duration		la durée de l'animation, en millisecondes
 * @param		{object}		options			tableau associatif contenant les options supplémentaires :
 * 														-   duration : integer - durée de l'animation, en millisecondes
 * 														-	frameRate : integer - nombre d'images par secondes
 * 														-	onFinish : function - fonction à appeler à la fin de l'animation
 * 
 * @returns		{void}
 */
function fade (elem, to, from, options) {
	
	// initialisation des paramètre principaux
	this.elem = elem || document.body;
    
    
	this.to = to!==undefined ? to : 1;
	var st = this.elem.style;
	this.from = (from===undefined ? ( !st.opacity&&st.opacity!==0 ? (this.to>0?0:1) : parseFloat(st.opacity) ) : from);
	
	// initialisation des options
	options = options || {};
	this.duration = options.duration || 2000;
	this.frameRate = options.frameRate || 30;
	this.onFinish = options.onFinish;
	
	// calculs pour découpage de l'animation en plusieurs étapes
	this.totalFrames = Math.ceil(this.duration/1000*this.frameRate);
	this.perFrame = (this.to-this.from)/this.totalFrames;
	this.frameNb = 0;
	
	// utile pour les setTimeout
	var self = this;



    /**
     * next
     * -------------------------------------------------------------------------
     * lance l'étape suivante de l'animation
     * 
	 * @returns		{void}
     * 
     */
    this.next = function () {
		this.prog = setTimeout (
			function(){self.frame();},
			1000/this.frameRate
		);
	};
		
	
	/**
	 * frame()
	 * -------------------------------------------------------------------------
	 * exécute une étape de l'animation
	 */
	this.frame = function () {
		// règle l'opacité de l'élément
		setOpacity(this.elem, this.from + this.perFrame*this.frameNb);
		
		// si anim terminée
        if ( this.frameNb===this.totalFrames ) {
				setOpacity(this.elem, this.to);
                if (typeof this.onFinish=='function') { setTimeout(this.onFinish,1); } // fonction callback
                }
				
        // sinon lancer le frame suivant
        else {
                this.frameNb++;
                this.next();
        }
	};
	
	
	// lancer la première étape de l'anim
    
	this.next();
}
