/**
 * Le gestionnaire pour les sélécteurs miniatures
 */
petzl.views.ThumbsSelector = function (pSelector, pOptions)
{
	// ------- PRIVATE PROPERTIES --------
	// Redéclarer cet élément
	var that = this;
	
	// Cibler le sélécteur
	var element = $(pSelector);
	
	// Cibler les boutons
	var buttons = element.find(".thumb");
	
	var hover = element.find(".thumb");

	// L'index séléctionné
	var currentIndex = 0;

	var slideWheels = [];
	
	// Les options
	var options = $.extend({
		intro: true,
		index: 0,
		alpha : false,
		color : ""
	}, pOptions);
	
	// ------- PUBLIC PROPERTIES --------
	// Le handler externe de changement
	this.onChange;
	

	// ---------- CONSTRUCTOR -----------
	function init ()
	{
		if(options.color){
			$('.loader').each(function(index){
				// Calculer le framerate pour avoir une durée de 4 secondes
				var slideWheel = new that.slideWheel($(this), (options.color != "") ? options.color : "o", 64 / 4, function(){
					slideWheel.goToEnd();
					slideWheel.stop();
				});
				slideWheels[index] = slideWheel;
			});
		}
		// Faire l'animation d'intro
		if (options.intro)
			that.intro();
		
		// Séléctionner l'index par défaut
		if (options.index != 0)
			that.select(options.index);
		
		// Applique l'alpha sur le premier élément
		if (options.alpha == true){
			var indexToShow = options.index - 1;
			$(buttons).not(':eq('+indexToShow+')').css('opacity', 0.5);
		}

		// Ecouter les clics
		buttons.click(buttonClickHandler).touchr({});
	}

	// -------- PRIVATE METHODS ---------
	// Clic sur un bouton
	function buttonClickHandler (event)
	{
		// Calculer l'index
		var computedIndex = buttons.index(this) + 1;
		
		// Si c'est différent
		if (computedIndex != currentIndex)
		{
			// Récupérer l'index et séléctionner
			that.select(computedIndex);
	
			// Dispatcher
			if (that.onChange)
				that.onChange(computedIndex);
		}
		
		// Pas suivre le lien
		event.stopPropagation();
		return false;
	}

	// -------- PUBLIC METHODS ---------
	// Animation d'intro
	this.intro = function (pThen)
	{
		// Afficher les boutons 1 à 1
		buttons.each(function (i, el) {
			$(this).stop().css({
				top: 100
			}).delay((buttons.length - i) * 100 + 200).animate({
				top: 0
			}, {
				duration: 400,
				easing: "easeOutBack",
				complete: (i == buttons.length - 1) ? pThen : null
			});
		});

		// Afficher le container
		element.css("display", "block");
	};
	
	// Séléctionner un index (0 pour déselectionner)
	this.select = function (pIndex)
	{
		// Si l'index change
		if (currentIndex != pIndex)
		{
			// Enregistrer l'index
			currentIndex = pIndex;
			
			// Supprimer toutes les classes selected
			buttons.removeClass("selected");

			// Cibler grâce à l'index et ajouter la classe
			$(buttons.get(pIndex - 1)).addClass("selected");
			
			
			if(options.color){
				// Appliquer le gif avec timer
				that.applyGif(pIndex);
			}
		}
	};
	
	this.restartThumb = function(){
		// On va au début du thumb (Full white) et on commence
		slideWheels[currentIndex - 1].goToStart();
		slideWheels[currentIndex - 1].start();
		
	};
	
	this.pauseThumb = function(){
		// On va à la fin et on arrête (Full color)
		slideWheels[currentIndex - 1].goToStart();
		slideWheels[currentIndex - 1].stop();
	};
	
	
	// Applique le gif sur le thumb sélectionné
	this.applyGif = function(pIndex){
		
		// On arrête tous les thumbs par précaution
		for (wheel in slideWheels)
		{
			slideWheels[wheel].goToEnd();
			slideWheels[wheel].stop();
		}
		
		// On commence le bon thumb
		slideWheels[pIndex - 1].goToStart();
		slideWheels[pIndex-1].start();
	};
	

	/**
	 * Créer un nouvelle SlideWheel sur un élément DOM
	 * @params pSelector : Le sélecteur jQuery de l'élément à cibler
	 * @params pColor : La couleur à afficher ("y" pour jaune, "o" pour orange)
	 * @params pFrameRate : Le nombre d'images par seconde pour l'animation. Permet de prédéfinir la durée de l'animation
	 * @params pOnAnimationEndedHandler : Handler appelé lorsque l'animation est terminée
	 */
	this.slideWheel = function(pSelector, pColor, pFrameRate, pOnAnimationEndedHandler)
	{
		// Garder l'instance dans le scope
		var that = this;

		// Cibler l'élément
		var element = pSelector;

		// La clé de l'interval de l'animation
		var interval = -1;

		// L'animation en cours et le nombre d'animations max
		var currentAnimationFrame = 0;
		var totalFrames = 64;

		// Les dimensions du sprite
		var elementSize = 32;
		var spriteWidth = 256;

		// Récupérer le framerate depuis les paramètres
		// Mettre une valeur par défaut si la valeur en paramètres n'est pas bonne
		var frameRate = (pFrameRate > 0 && pFrameRate <= 60) ? pFrameRate : 12;
		
		// Récupérer la couleur depuis les paramètres
		var color = (pColor == "y" || pColor == "o") ? pColor : "o";

		// Les offsets pour décaller le sprite
		var leftOffset;
		var topOffset;
		
		// Le décalage d'image selon la couleur
		var colorOffset = 0;

		/**
		 * Actualiser la roue depuis l'interval
		 */
		this.updateWheelInterval = function ()
		{
			// Passer à la frame suivante
			currentAnimationFrame ++;

			// Limiter dans le nombre de frame disponible
			if (currentAnimationFrame >= totalFrames)
			{
				// Limiter
				currentAnimationFrame = totalFrames;

				// Appeler le handler de fin d'animation si disponible
				if (pOnAnimationEndedHandler != null)
				{
					pOnAnimationEndedHandler();
				}
			}
			else
			{
				// Actualiser l'image
				that.updateFrame();
			}
		};

		/**
		 * Actualiser l'image pour la frame en cours
		 */
		this.updateFrame = function ()
		{
			// Calculer le décallage d'images selon la couleur
			colorOffset = (color == "y" ? 64 : 0);
		
			// Calculer le décallage du sprite pour cibler la bonne image
			leftOffset = - ((currentAnimationFrame + colorOffset) * elementSize) % spriteWidth;
			topOffset = - Math.floor(((currentAnimationFrame + colorOffset) * elementSize) / spriteWidth) * elementSize;

			// Appliquer le décallage sur l'élément
			element.css({
				backgroundPosition: leftOffset / 2 + "px " + topOffset / 2 + "px"
			});
		};
		
		this.goToStart= function(){
			this.goTo(0);
			this.stop();
		};
		
		this.goToEnd= function(){
			this.goTo(63);
			this.stop();
		};

		/**
		 * Démarrer l'animation
		 */
		this.start = function ()
		{
			// Arrêter l'interval déjà en cours
			this.stop();

			// Lancer la boucle et enregistrer la clé de l'interval
			interval = window.setInterval(that.updateWheelInterval, 1000 / frameRate);
		};

		/**
		 * Arrêter l'animation
		 */
		this.stop = function ()
		{
			// Si on a un interval
			if (interval != -1)
			{
				// On le vire
				window.clearInterval(interval);
			}

			// Signaler dans la clé de l'interval qu'il n'y en a plus
			interval = -1;
		};

		/**
		 * Aller à une image en particulier
		 */
		this.goTo = function (pFrame)
		{
			// Cibler l'image et limiter
			currentAnimationFrame = Math.max(0, Math.min(pFrame, totalFrames));

			// Actualiser
			this.updateFrame();
		};

		// Ajouter la classe à l'élément pour l'image
		element.addClass("slideWheel");

		// Actualiser la première image
		this.updateFrame();
		
		this.goToEnd();
	};

	// Initialiser
	init();
};