
/**
 * Constructeur du carrousel
 * 
 * @param string idImgsContainer		Id du conteneur des images
 * @param string idImgActuContainer		Id du conteneur pour afficher le nom de l'image actuelle (alt)
 * @param string idLiensContainer		Id du conteneur des liens (pour changer d'image)
 * @param int speedCarrousel			Vitesse de défilement du carrousel (entre chaque image). Exprimé en millisecondes
 * @param int speedAnimating			[Optionnel] Vitesse de l'animation. Exprimé en millisecondes. Si non saisi, aucune animation.
 * @param object options				[Optionnel] Options éventuelles de configuration avancée du carrousel 
 */
function RSPlug_Carrousel (idImgsContainer, idImgActuContainer, idLiensContainer, speedCarrousel, speedAnimating, options){
	// Mise à zéro des variables
	this.lastImg = null;					// Dernière image vue (pour gérer le display: none)
	this.newImg = null;
	this.nbImgs = null;
	
	// Préparation de l'objet de configuration
	this.config = {
		setImgsContainerPosition: true,		// On force le position: relative car on place les images en absolute dedans
		startImgIndex: 0,					// Index de l'image de démarrage du carrousel
		loadAltText: true,					// Doit-on charger les textes du "alt" dans les numéros ?
		waitEndFaddingBeforeChange: false,	// Doit-on attendre la fin du fondu avant de pouvoir changer d'image ?
		percentFaddingToChangeLink: 50,		// Pourcentage à atteindre pour changer le lien de l'image actuelle
		useFaddingToChange: false,			// Doit-on utiliser le fondu (si fondu) lorsqu'on change d'image via un clic ?
		changeImgCallback: null,			// Callback a appeler lorsqu'on commence le changement de l'image
		finishImgCallback: null,			// Callback a appeler lorsqu'on termine le changement de l'image
		animation: 'linearFadding',			// Type d'animation à utiliser (double fondu linéaire: linearFadding; fondu simple: fadding; deplacement: rtl, tlr, ttb, btt)
		animateLastImg: true,				// Doit-on animer l'image active
		defaultZIndex: 40,					// ZIndex par défaut à appliquer aux images
		maxImgs: 0,							// Nombre maximum d'images pour le carrousel (0 = sans limite)
		liMode: false,						// Le carrousel doit-il boucler sur les éléments "li" au lieu de sur les images ?
		dlMode: false						// Carrousel avancé par un dl dt dd ? (dt pour les numéro, dd pour les images)
	};
	if (options){
		if (null !== options.setImgsContainerPosition && !options.setImgsContainerPosition){
			this.config.setImgsContainerPosition = false;
		}
		if (null !== options.startImgIndex && options.startImgIndex > 0 && !isNaN(options.startImgIndex)){
			this.config.startImgIndex = parseInt(options.startImgIndex);
		}
		if (null !== options.loadAltText && !options.loadAltText){
			this.config.loadAltText = false;
		}
		if (null !== options.waitEndFaddingBeforeChange && options.waitEndFaddingBeforeChange){
			this.config.waitEndFaddingBeforeChange = true;
		}
		if (null !== options.percentFaddingToChangeLink && options.percentFaddingToChangeLink >= 0 && options.percentFaddingToChangeLink <= 100 && !isNaN(options.percentFaddingToChangeLink)){
			this.config.percentFaddingToChangeLink = parseInt(options.percentFaddingToChangeLink);
		}
		if (null !== options.useFaddingToChange && options.useFaddingToChange){
			this.config.useFaddingToChange = true;
		}
		if (null !== options.changeImgCallback && options.changeImgCallback){
			this.config.changeImgCallback = options.changeImgCallback;
		}
		if (null !== options.finishImgCallback && options.finishImgCallback){
			this.config.finishImgCallback = options.finishImgCallback;
		}
		if (null !== options.animation && options.animation){
			this.config.animation = options.animation;
		}
		if (null !== options.animateLastImg && !options.animateLastImg){
			this.config.animateLastImg = false;
		}
		if (null !== options.maxImgs && !isNaN(options.maxImgs) && options.maxImgs > 0){
			this.config.maxImgs = options.maxImgs;
		}
		if (null !== options.liMode && options.liMode){
			this.config.liMode = options.liMode;
		}
		if (null !== options.dlMode && options.dlMode){
			this.config.dlMode = options.dlMode;
		}
	}
	
	// Récupération des conteneurs
	this.imgsContainer = document.getElementById(idImgsContainer);
	this.imgActuContainer = document.getElementById(idImgActuContainer);
	this.liensContainer = document.getElementById(idLiensContainer);
	this.liensContainer.style.zIndex = (this.config.defaultZIndex +3);
	
	// Défilement du carrousel
	this.toCarrousel = null;				// Timeout de défilement du carrousel
	this.speedCarrousel = speedCarrousel;	// Vitesse de défilement du carrousel (en millisecondes)
	
	// Fondu du carrousel
	if (speedAnimating && !isNaN(speedAnimating) && speedAnimating > 0){
		this.speedAnimating = parseFloat(speedAnimating / 100);
		this.timeoutsFadding = [];			// Timeouts de l'effet de fondu
		this.useFadding = true;				// Utilise t-on l'effet de fondu ?
	} else {
		this.useFadding = false;			// Utilise t-on l'effet de fondu ?
	}
	this.fadding = false;					// Témoin de l'état de l'effet de fondu (un fondu est-il en court)
	
	// Récupération des images du carrousel + Mise en forme de ces dernières
	if (this.config.liMode){
		this.imgs = this.imgsContainer.getElementsByTagName('li');
	} else if (this.config.dlMode){
		this.imgs = this.imgsContainer.getElementsByTagName('dd');
		this.imgsTitles = this.imgsContainer.getElementsByTagName('dt');
		for (var i=0; i<this.imgsTitles.length; i++){
			this.imgsTitles[i].style.display = 'none';
		}
		if (this.imgs.length != this.imgsTitles.length){
			this.dlMode = false;
		}
	} else {
		this.imgs = this.imgsContainer.getElementsByTagName('img');
	}
	this.nbImgs = (this.config.maxImgs > 0 && this.config.maxImgs < this.imgs.length) ? this.config.maxImgs : this.imgs.length;
	if (this.nbImgs == 0){
		return false;
	}
	if (this.config.startImgIndex < 0 || this.config.startImgIndex >= this.nbImgs){
		this.config.startImgIndex = 0;
	}
	if (this.config.setImgsContainerPosition){ 
		this.imgsContainer.style.position = 'relative';	
	}
	if (this.nbImgs > 1){
		for (var i=0; i<this.imgs.length; i++){
			this.imgs[i].style.position = 'absolute';
			this.imgs[i].style.left = 0;
			this.imgs[i].style.top = 0;
			this.imgs[i].style.display = 'none';
			this.imgs[i].style.zIndex = this.config.defaultZIndex;
		}
		this.show(this.config.startImgIndex);
	}
}

/**
 * Fonction d'affichage d'une image du carrousel (sans fondu)
 */
RSPlug_Carrousel.prototype.show = function (imgIndex){
	if (this.fadding){
		return false;
	}
	if (null !== this.toCarrousel){
		clearTimeout(this.toCarrousel);
	}
	
	if (this.config.animation == 'rtl' || this.config.animation == 'ltr'){
		this.imgs[imgIndex].style.left = 0;
	}
	if (this.config.animation == 'btt' || this.config.animation == 'ttb'){
		this.imgs[imgIndex].style.top = 0;
	}
	this.imgs[imgIndex].style.display = '';
	this.lastImg = this.imgs[imgIndex];
	this.imgActuContainer.innerHTML = (this.config.liMode || this.config.dlMode ? '' : this.imgs[imgIndex].alt.replace(/\|\|/g, '<br />'));
	this.liensContainer.innerHTML = '';
	for (var i=0; i<this.nbImgs; i++){
		this.liensContainer.appendChild(this.createLink(i, (i == imgIndex)));
	}
	
	this.prepareNext (imgIndex);
};

/**
 * Fonction qui gère le défilement du carrousel (avec ou sans fondu)
 */
RSPlug_Carrousel.prototype.prepareNext = function (imgIndex){
	if (this.nbImgs > 1){
		var next = (imgIndex +1 < this.nbImgs) ? imgIndex +1: 0;
		var inst = this;
		if (this.config.animation == 'rtl' || this.config.animation == 'ltr' || this.config.animation == 'ttb' || this.config.animation == 'btt'){
			this.toCarrousel = setTimeout(function (){ inst.toCarrousel = null; inst.slideTo(next); }, this.speedCarrousel);
		} else if (this.useFadding){
			this.toCarrousel = setTimeout(function (){ inst.toCarrousel = null; inst.fadeTo(next); }, this.speedCarrousel);
		} else {
			this.toCarrousel = setTimeout(function (){ inst.toCarrousel = null; inst.goTo(next); }, this.speedCarrousel);
		}
	}
};

/**
 * Fonction qui crée les liens de numéro d'image
 */
RSPlug_Carrousel.prototype.createLink = function (imgIndex, actif){
	var link = document.createElement('a');
	link.href = '#';
	var inst = this;
	if (this.config.useFaddingToChange && this.useFadding){
		link.onclick = function(){
			if (null !== inst.toCarrousel){
				clearTimeout(inst.toCarrousel);
				inst.toCarrousel = null;
			}
			if (null !== inst.newImg && inst.imgs[imgIndex] == inst.newImg){
				return false;
			}
			inst.newImg = inst.imgs[imgIndex];
			inst.clearFadding(inst.lastImg);
			if (inst.imgs[imgIndex] == inst.lastImg){
				inst.goTo(imgIndex);
			} else if (inst.config.animation == 'rtl' || inst.config.animation == 'ltr' || inst.config.animation == 'ttb' || inst.config.animation == 'btt'){
				inst.slideTo(imgIndex);
			} else {
				inst.fadeTo(imgIndex);
			}
			return false;
		};
	} else {
		link.onclick = function(){
			inst.goTo(imgIndex);
			return false;
		};
	}
	if (actif){
		link.className = 'actif';
	}
	if (this.config.liMode){
		link.innerHTML = '<strong>' + (imgIndex +1) + '</strong>';
	} else if (this.config.dlMode){
		link.innerHTML = this.imgsTitles[imgIndex].innerHTML;
	} else if (this.config.loadAltText) {
		link.innerHTML = this.imgs[imgIndex].alt.replace(/\|\|/g, ' ') + ' <strong>' + (imgIndex +1) + '</strong>';
	} else {
		link.innerHTML = '<strong>' + (imgIndex +1) + '</strong>';
	}
	return link;
};

/**
 * Fonction pour se rendre à une image par son index, sans fondu
 */
RSPlug_Carrousel.prototype.goTo = function (imgIndex){
	if (this.fadding){
		if (this.config.waitEndFaddingBeforeChange){
			return false;
		}
		this.clearFadding();
	}
	this.newImg = null;
	if (null !== this.config.changeImgCallback){
		this.config.changeImgCallback(this);
	}
	if (null !== this.lastImg){
		this.lastImg.style.display = 'none';
	}
	this.show(imgIndex);
	if (null !== this.config.finishImgCallback){
		this.config.finishImgCallback(this);
	}
};

/**
 * Fonction pour se rendre à une image par son index, avec fondu
 */
RSPlug_Carrousel.prototype.fadeTo = function (imgIndex){
	this.fadding = true;
	this.timeoutsFadding = [];

	this.setOpacity(this.imgs[imgIndex], 0);
	this.imgs[imgIndex].style.display = '';
	
	var inst = this;
	var index = imgIndex;
	
	var selectImgNumber = function(){
		inst.imgActuContainer.innerHTML = (inst.config.liMode || inst.config.dlMode ? '' : inst.imgs[index].alt.replace(/\|\|/g, '<br />'));
		inst.liensContainer.innerHTML = '';
		for (var i=0; i<inst.imgs.length; i++){
			inst.liensContainer.appendChild(inst.createLink(i, (i == index)));
		}
	};

	if (null !== this.config.changeImgCallback){
		this.config.changeImgCallback(this);
	}
	
	this.lastImg.style.zIndex = (this.config.defaultZIndex +1);
	this.imgs[imgIndex].style.zIndex = (this.config.defaultZIndex +2);
	for (var i=0; i<=100; i++){
		var delai = this.speedAnimating *i;
		if (this.config.animation == 'linearFadding'){
			this.timeoutsFadding.push(this.setFadding(this.lastImg, (100 -i), delai));
		} else if (this.config.animation == 'fadding' && i == 0){
			this.timeoutsFadding.push(this.setFadding(this.lastImg, (100 -i), 0));
		} 
		this.timeoutsFadding.push(this.setFadding(this.imgs[imgIndex], i, delai));
		if (i == this.config.percentFaddingToChangeLink){
			this.timeoutsFadding.push(setTimeout(selectImgNumber, delai));
		}
	}
	
	var cleaner = function (){
		if (null !== inst.lastImg){
			inst.lastImg.style.display = 'none';
			inst.setOpacity(inst.lastImg, 100);
		}
		inst.imgs[index].style.display = '';
		inst.lastImg = inst.imgs[index];
		inst.lastImg.style.zIndex = inst.config.defaultZIndex;
		inst.imgs[index].style.zIndex = inst.config.defaultZIndex;
		inst.prepareNext (index);
		inst.fadding = false;
		inst.newImg = null;

		if (null !== inst.config.finishImgCallback){
			inst.config.finishImgCallback(inst);
		}
	};
	this.timeoutsFadding.push(setTimeout(cleaner, delai));
};

/**
 * Fonction pour se rendre à une image par son index, avec deplacement
 */
RSPlug_Carrousel.prototype.slideTo = function (imgIndex){
	this.fadding = true;
	this.timeoutsFadding = [];
	
	this.imgs[imgIndex].style.display = '';

	if (this.config.animation == 'rtl' || this.config.animation == 'ltr'){
		var longueurDeplacement = (this.imgsContainer.offsetWidth || this.imgsContainer.parentNode.offsetWidth || this.lastImg.offsetWidth);
	} else {
		var longueurDeplacement = (this.imgsContainer.offsetHeight || this.imgsContainer.parentNode.offsetHeight || this.lastImg.offsetHeight);
	}
	var step = longueurDeplacement / 100;
	
	switch (this.config.animation){
		case 'rtl':		
			this.imgs[imgIndex].style.left = longueurDeplacement +'px';		
			break;
		case 'ltr':		
			this.imgs[imgIndex].style.left = longueurDeplacement *-1 +'px'; 	
			break;
		case 'ttb':		
			this.imgs[imgIndex].style.top = longueurDeplacement *-1 +'px'; 
			break;
		case 'btt':		
			this.imgs[imgIndex].style.top = longueurDeplacement +'px';		
			break;
	}
	
	var inst = this;
	var index = imgIndex;
	
	var selectImgNumber = function(){
		inst.imgActuContainer.innerHTML = (inst.config.liMode || inst.config.dlMode ? '' : inst.imgs[index].alt.replace(/\|\|/g, '<br />'));
		inst.liensContainer.innerHTML = '';
		for (var i=0; i<inst.imgs.length; i++){
			inst.liensContainer.appendChild(inst.createLink(i, (i == index)));
		}
	};
	
	if (null !== this.config.changeImgCallback){
		this.config.changeImgCallback(this);
	}
	
	this.lastImg.style.zIndex = (this.config.defaultZIndex +1);
	this.imgs[imgIndex].style.zIndex = (this.config.defaultZIndex +2);
	
	for (var i=0; i<=100; i++){
		var delai = this.speedAnimating *i;

		switch (this.config.animation){
			case 'rtl':		
				this.timeoutsFadding.push(this.setSlide(this.imgs[imgIndex], true, (i *-1 * step +longueurDeplacement), delai));
				if (this.config.animateLastImg){
					this.timeoutsFadding.push(this.setSlide(this.lastImg, true, (i *-1 * step), delai));
				}
				break;
			case 'ltr':		
				this.timeoutsFadding.push(this.setSlide(this.imgs[imgIndex], true, (i * step -longueurDeplacement), delai));		
				if (this.config.animateLastImg){
					this.timeoutsFadding.push(this.setSlide(this.lastImg, true, (i * step), delai));
				}
				break;
			case 'ttb':		
				this.timeoutsFadding.push(this.setSlide(this.imgs[imgIndex], false, (i * step -longueurDeplacement), delai));		
				if (this.config.animateLastImg){
					this.timeoutsFadding.push(this.setSlide(this.lastImg, false, (i * step), delai));
				}
				break;
			case 'btt':		
				this.timeoutsFadding.push(this.setSlide(this.imgs[imgIndex], false, (i *-1 * step +longueurDeplacement), delai));		
				if (this.config.animateLastImg){
					this.timeoutsFadding.push(this.setSlide(this.lastImg, false, (i *-1 * step), delai));
				}
				break;
		}
		if (i == this.config.percentFaddingToChangeLink){
			this.timeoutsFadding.push(setTimeout(selectImgNumber, delai));
		}
	}
	
	var cleaner = function (){
		if (null !== inst.lastImg){
			inst.lastImg.style.display = 'none';
		}
		inst.imgs[index].style.display = '';
		inst.lastImg = inst.imgs[index];
		inst.lastImg.style.zIndex = inst.config.defaultZIndex;
		inst.imgs[index].style.zIndex = inst.config.defaultZIndex;
		inst.prepareNext (index);
		inst.fadding = false;
		inst.newImg = null;
		
		if (null !== inst.config.finishImgCallback){
			inst.config.finishImgCallback(inst);
		}
	};
	this.timeoutsFadding.push(setTimeout(cleaner, delai));
};

/**
 * Fonction pour interrompre le fondu (pour changer d'image par exemple)
 */
RSPlug_Carrousel.prototype.clearFadding = function(exceptImg){
	if (this.useFadding){
		for (var i=0; i<this.timeoutsFadding.length; i++){
			if (this.timeoutsFadding[i]){
				clearTimeout(this.timeoutsFadding[i]);
			}
		}
		if (null !== this.lastImg){
			for (var i=0; i<this.nbImgs; i++){
				if (null !== exceptImg && this.imgs[i] == exceptImg){
					this.setOpacity(this.imgs[i], 100);
					continue;
				}
				this.imgs[i].style.display = 'none';
				this.setOpacity(this.imgs[i], 100);
			}
		}
		this.fadding = false;
	}
};

/**
 * Fonction de déclaration du fondu
 */
RSPlug_Carrousel.prototype.setFadding = function (obj, opacity, delai){
	var inst = this;
	return setTimeout(function(){ inst.setOpacity(obj, opacity); }, delai);
};

/**
 * Fonction de déclaration du déplacement
 */
RSPlug_Carrousel.prototype.setSlide = function (obj, isLeftPos, position, delai){
	var inst = this;
	if (isLeftPos){
		return setTimeout(function(){ obj.style.left = position +'px'; }, delai);
	} else {
		return setTimeout(function(){ obj.style.top = position +'px'; }, delai);
	}
};

/**
 * Fonction de déclaration d'opacité (multi-navigateur)
 */
RSPlug_Carrousel.prototype.setOpacity = function (obj, opak){
	if (obj && obj.style){
		opak = parseInt(opak);
		obj.style.opacity = (opak / 100);
		obj.style.MozOpacity = (opak / 100);
		obj.style.KhtmlOpacity = (opak / 100);
		obj.style.filter = 'alpha(opacity=' + opak + ')';
	}
};


