
/**
 * 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.lastImgIndex = null;
	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
		percentFaddingToChangeLinkOnClick: 0,	// 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
		slideByOrder: false,					// Doit-on animer selon l'ordre des images ?
		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)
		directChildsMode: false,				// Carrousel avancé par enfant directs ? (par exemple les divs)
		dlFollowLink: false,					// Les liens doivent-ils changer de page (suivi du lien) ou doit-on juste changer les images du carrousel ? (ne fonctionne qu'en mode DL)
		pauseIfOver: false						// Le carrousel doit-il se mettre en pause lorsqu'il est survolé ?
	};
	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.percentFaddingToChangeLinkOnClick && options.percentFaddingToChangeLinkOnClick >= 0 && options.percentFaddingToChangeLinkOnClick <= 100 && !isNaN(options.percentFaddingToChangeLinkOnClick)){
			this.config.percentFaddingToChangeLinkOnClick = parseInt(options.percentFaddingToChangeLinkOnClick);
		}
		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.slideByOrder && options.slideByOrder){
			this.config.slideByOrder = true;
		}
		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;
		}
		if (null !== options.directChildsMode && options.directChildsMode){
			this.config.directChildsMode = options.directChildsMode;
		}
		if (null !== options.dlFollowLink && options.dlFollowLink){
			this.config.dlFollowLink = options.dlFollowLink;
		}
		if (null !== options.pauseIfOver && options.pauseIfOver){
			this.config.pauseIfOver = true;
		}
	}
	
	// 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)
	
	this.onPause = false;					// Témoin de l'état de la pause (le carrousel est-il en pause)
	if (this.config.pauseIfOver){
		var inst = this;
		this.imgsContainer.onmouseover = function (){ inst.onPause = true; };
		this.imgsContainer.onmouseout = function (){ inst.onPause = false; };
	}
	
	// Récupération des images du carrousel + Mise en forme de ces dernières
	if (this.config.liMode){
		this.slides = this.imgsContainer.getElementsByTagName('li');
	} else if (this.config.dlMode){
		this.slides = 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.slides.length != this.imgsTitles.length){
			this.config.dlMode = false;
		}
	} else if (this.config.directChildsMode){
		this.slides = [];
		var childs = this.imgsContainer.childNodes;
		for (var i=0; i<childs.length; i++){
			if (childs[i].nodeType == 1){
				this.slides.push(childs[i]);
			}
		}
	} else {
		this.slides = this.imgsContainer.getElementsByTagName('img');
	}
	this.nbImgs = (this.config.maxImgs > 0 && this.config.maxImgs < this.slides.length) ? this.config.maxImgs : this.slides.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.slides.length; i++){
			this.slides[i].style.position = 'absolute';
			this.slides[i].style.left = 0;
			this.slides[i].style.top = 0;
			this.slides[i].style.display = 'none';
			this.slides[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.slides[imgIndex]){
		if (this.config.animation == 'rtl' || this.config.animation == 'ltr'){
			this.slides[imgIndex].style.left = 0;
		}
		if (this.config.animation == 'btt' || this.config.animation == 'ttb'){
			this.slides[imgIndex].style.top = 0;
		}
		this.slides[imgIndex].style.display = '';
		this.lastImg = this.slides[imgIndex];
	}
	this.lastImgIndex = imgIndex;
	this.imgActuContainer.innerHTML = (this.config.liMode || this.config.dlMode || this.config.directChildsMode ? '' : this.slides[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) ? parseInt(imgIndex +1): 0;
		//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 (){ if (inst.onPause){ inst.prepareNext(imgIndex); } else { inst.toCarrousel = null; inst.slideTo(next); } }, this.speedCarrousel);
		} else if (this.useFadding){
			this.toCarrousel = setTimeout(function (){ if (inst.onPause){ inst.prepareNext(imgIndex); } else { inst.toCarrousel = null; inst.fadeTo(next); } }, this.speedCarrousel);
		} else {
			this.toCarrousel = setTimeout(function (){ if (inst.onPause){ inst.prepareNext(imgIndex); } else { 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 = null;
	var dlFollowLink = (this.config.dlMode && this.config.dlFollowLink);
//	if (!document.getElementById('eltDebug')){
//		var eltDebug = document.createElement('div');
//		eltDebug.id = 'eltDebug';
//		eltDebug.style.display = 'none';
//		document.body.appendChild(eltDebug);
//	} else {
//		var eltDebug = document.getElementById('eltDebug');
//	}
//	eltDebug.innerHTML = 'dlFollowLink: ' + (dlFollowLink ? 'oui' : 'non');
	if (dlFollowLink){
//		eltDebug.innerHTML = this.imgsTitles[imgIndex].innerHTML;
		var links = this.imgsTitles[imgIndex].getElementsByTagName('a');
		if (links[0]){
			link = links[0].cloneNode(true);
		}
	}
	if (null === link){
		var link = document.createElement('a');
		link.href = '#';
	}
	var inst = this;
	if (this.config.useFaddingToChange && this.useFadding){
		link.onclick = function(){
			if (dlFollowLink){
				return true;
			}
			if (inst.config.waitEndFaddingBeforeChange && inst.fadding){
				return false;
			}
			if (null !== inst.toCarrousel){
				clearTimeout(inst.toCarrousel);
				inst.toCarrousel = null;
			}
			if (null !== inst.newImg && inst.slides[imgIndex] == inst.newImg){
				return false;
			}
			inst.newImg = inst.slides[imgIndex];
			inst.clearFadding(inst.lastImg);
			if (inst.slides[imgIndex] == inst.lastImg){
				inst.goTo(imgIndex, true);
			} else if (inst.config.animation == 'rtl' || inst.config.animation == 'ltr' || inst.config.animation == 'ttb' || inst.config.animation == 'btt'){
				inst.slideTo(imgIndex, true);
			} else {
				inst.fadeTo(imgIndex, true);
			}
			return false;
		};
	} else {
		link.onclick = function(){
			if (dlFollowLink){
				return true;
			}
			if (inst.config.waitEndFaddingBeforeChange && inst.fadding){
				return false;
			}
			inst.goTo(imgIndex, true);
			return false;
		};
	}
	if (this.config.liMode || this.config.directChildsMode){
		link.innerHTML = '<strong>' + (imgIndex +1) + '</strong>';
	} else if (this.config.dlMode){
		if (!dlFollowLink){
			link.innerHTML = this.imgsTitles[imgIndex].innerHTML;
		}
	} else if (this.config.loadAltText) {
		link.innerHTML = this.slides[imgIndex].alt.replace(/\|\|/g, ' ') + ' <strong>' + (imgIndex +1) + '</strong>';
	} else {
		link.innerHTML = '<strong>' + (imgIndex +1) + '</strong>';
	}
	if (actif){
		link.className = 'actif';
	}
	return link;
};

/**
 * Fonction pour se rendre à une image par son index, sans fondu
 */
RSPlug_Carrousel.prototype.goTo = function (imgIndex, fromClick){
	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, fromClick){
	this.fadding = true;
	this.timeoutsFadding = [];

	if (!this.slides[imgIndex]){
		if (!document.getElementById('debug') && document.getElementById('en-tete')){
			var debug = document.createElement('div');
			debug.id = 'debug';
			debug.style.display = 'none';
			document.getElementById('en-tete').appendChild(debug);
		}
		if (document.getElementById('debug')){
			document.getElementById('debug').innerHTML = '['+imgIndex + ' : ' + typeof(imgIndex)+']';
		}
		this.fadding = false;
		this.prepareNext(imgIndex);
		return false;
	}
	
	
	this.setOpacity(this.slides[imgIndex], 0);
	this.slides[imgIndex].style.display = '';
	
	var inst = this;
	
	var selectImgNumber = function(){
		inst.imgActuContainer.innerHTML = (inst.config.liMode || inst.config.dlMode || inst.config.directChildsMode ? '' : inst.slides[imgIndex].alt.replace(/\|\|/g, '<br />'));
		inst.liensContainer.innerHTML = '';
		for (var i=0; i<inst.slides.length; i++){
			inst.liensContainer.appendChild(inst.createLink(i, (i == imgIndex)));
		}
	};

	if (null !== this.config.changeImgCallback){
		this.config.changeImgCallback(this);
	}
	
	this.lastImg.style.zIndex = (this.config.defaultZIndex +1);
	this.slides[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.slides[imgIndex], i, delai));
		if ((i == this.config.percentFaddingToChangeLink && !fromClick) || (i == this.config.percentFaddingToChangeLinkOnClick && fromClick)){
			this.timeoutsFadding.push(setTimeout(selectImgNumber, delai));
		}
	}
	
	var imageIndex = imgIndex;
	var cleaner = function (){
		if (null !== inst.lastImg){
			inst.lastImg.style.display = 'none';
			inst.setOpacity(inst.lastImg, 100);
		}
		inst.lastImgIndex = imageIndex;
		inst.lastImg = inst.slides[imageIndex];
		inst.lastImg.style.zIndex = inst.config.defaultZIndex;
		inst.slides[imageIndex].style.display = '';
		inst.slides[imageIndex].style.zIndex = inst.config.defaultZIndex;
		inst.prepareNext(imageIndex);
		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, fromClick){
	var fromClick = (fromClick) ? true : false;
	this.fadding = true;
	this.timeoutsFadding = [];
	
	this.slides[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;
	
	var animation = this.config.animation;
	if (this.config.slideByOrder && fromClick && imgIndex < this.lastImgIndex){
		if (animation == 'rtl'){ animation = 'ltr'; }
		else if (animation == 'ltr'){ animation = 'rtl'; }
		else if (animation == 'ttb'){ animation = 'btt'; }
		else if (animation == 'btt'){ animation = 'ttb'; }
	}
	switch (animation){
		case 'rtl':		
			this.slides[imgIndex].style.left = longueurDeplacement +'px';		
			break;
		case 'ltr':		
			this.slides[imgIndex].style.left = longueurDeplacement *-1 +'px'; 	
			break;
		case 'ttb':		
			this.slides[imgIndex].style.top = longueurDeplacement *-1 +'px'; 
			break;
		case 'btt':		
			this.slides[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.config.directChildsMode ? '' : inst.slides[imgIndex].alt.replace(/\|\|/g, '<br />'));
		inst.liensContainer.innerHTML = '';
		for (var i=0; i<inst.slides.length; i++){
			inst.liensContainer.appendChild(inst.createLink(i, (i == imgIndex)));
		}
	};
	
	if (null !== this.config.changeImgCallback){
		this.config.changeImgCallback(this);
	}
	
	this.lastImg.style.zIndex = (this.config.defaultZIndex +1);
	this.slides[imgIndex].style.zIndex = (this.config.defaultZIndex +2);
	
	for (var i=0; i<=100; i++){
		var delai = this.speedAnimating *i;

		switch (animation){
			case 'rtl':		
				this.timeoutsFadding.push(this.setSlide(this.slides[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.slides[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.slides[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.slides[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 && !fromClick) || (i == this.config.percentFaddingToChangeLinkOnClick && fromClick)){
			this.timeoutsFadding.push(setTimeout(selectImgNumber, delai));
		}
	}
	
	var cleaner = function (){
		if (null !== inst.lastImg){
			inst.lastImg.style.display = 'none';
		}
		inst.slides[imgIndex].style.display = '';
		inst.lastImg = inst.slides[imgIndex];
		inst.lastImgIndex = imgIndex;
		inst.lastImg.style.zIndex = inst.config.defaultZIndex;
		inst.slides[imgIndex].style.zIndex = inst.config.defaultZIndex;
		inst.prepareNext (imgIndex);
		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 (!this.slides[i]){
					continue;
				}
				if (null !== exceptImg && this.slides[i] == exceptImg){
					this.setOpacity(this.slides[i], 100);
					continue;
				}
				this.slides[i].style.display = 'none';
				this.setOpacity(this.slides[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);
		if (navigator.userAgent.toLowerCase().indexOf('msie') >= 0){
			obj.style.filter = 'alpha(opacity=' + opak + ')';
		}	
	}
};



