/*
 * Plugin de scroll pour les conteneurs html.
 *
 * Utilisation : 
 *		$("div.aScroller").scrollbar();
 *		$("div.aScroller").scrollbar({cursorHeight:50});
 *
 * Version 1.0.3
 *
 * Dernière modif : 
 *		19/05/2011 : Règle le problème d'offset du contenu et du curseur lors d'un retour rapide à 0
 *		03/05/2011 : Règle le bug de mouseup sur les contenus (ex: flash) dans Google Chrome
 *
 *	Compression : http://dean.edwards.name/packer/
 */


(function($){
	
	/**
	 * Fonction disponible sur les éléments DOM qui permet d'ajouter un scroller javascript
	 * @param array params
	 *		updateTime - int : vitesse d'interval de déplacement en millisecondes
	 *		mousewheel - "auto"|bool : Utilisation du scroll souris (nécessite le script jquery.mousewheel)
	 *		wheelStep - "auto"|int : Vitesse de scroll lors d'un mousewheel
	 *		arrowStep - "auto"|int : Vitesse de scroll lors d'un appel de scrollUp et scrollDown
	 *		cursorHeight - "auto"|null|int : Hauteur à appliquer au curseur
	 *
	 *		"auto" : Valeur automatique
	 *		null : n'applique rien (à modifier par stylesheet)
	 *		int : Nombre fixe
	 */
	$.fn.scrollbar = function(params){
		
		// référances
		var $document = $(document);
		var $window = $(window);
		var $body = $(document.body);
		
		// paramètres par défaut + remplacement par user
		params = $.extend({
			updateTime : 1000 / 32,
			mousewheel : "auto",
			wheelStep : "auto",
			arrowStep : "auto",
			cursorHeight : "auto",
			debug : false 
		}, params);

		// si aucun autre slider n'a déjà créer d'event de mousemove
		if( ! $document.data("currentMouseX")){
			$document.mousemove(documentMouseMove);
		}
		
		// pour chaque items du sélecteur jquery
		return this.each(function(){
			var $conteneur = $(this);
			var $contenu;
			var $barre;
			var $curseur;
			var intervalDrag;
			var offsetY;
			var curseurHeight;
			var barreHeight;
			var contenuHeight;
			var pourcentage = 0;
			var wheelStep;
			var currentContentY = 0;

			if($conteneur.data("sliderInitialiser") == true){
				return;
			}

			$conteneur.data("sliderInitialiser", true);

			$contenu = $('<div class="contenuSlider"></div>');
			$barre = $('<div class="barreSlide"></div>');
			$curseur = $('<div class="curseurSlide"></div>');

			$conteneur.wrapInner($contenu);
			$barre.append($curseur);
			$contenu = $(".contenuSlider", $conteneur);

			$curseur.mousedown(startDragCurseur);
			$curseur.disableSelection();

			if($.browser.msie){
				$document.bind("mouseup", stopDragCurseur);
			}else{
				$window.bind("mouseup", stopDragCurseur);
			}
			
			// si le mousewheel est à true ou à auto et que le script jquery.mousewheel est présent
			if(params.mousewheel == true || params.mousewheel == "auto"){
				if($.event.special.mousewheel != undefined){
					$conteneur.bind("mousewheel", mouseWheelConteneur);
				}else if(params.mousewheel === true){
					debugScroll("Mousewheel script non disponible");
				}
			}

			// si le conteneur n'a pas de type de positionnement on le met relative
			if($conteneur.css("position") == "static") $conteneur.css("position", "relative");

			// overflow hidden afin de caché le contenu non-afficher
			$conteneur.css("overflow", "hidden");

			// styles du wrapper de contenu qui se déplacera lors du scroll
			$contenu.css({
				position : "relative",
				top : 0,
				left : 0,
				paddingTop : $conteneur.css("paddingTop"),
				paddingRight : $conteneur.css("paddingRight"),
				paddingBottom : $conteneur.css("paddingBottom"),
				paddingLeft : $conteneur.css("paddingLeft")
			});
			// styles par défaut de la barre
			$barre.css({
				position : "absolute",
				top : 0,
				right : 0,
				height : "100%",
				backgroundColor : "#C44"
			});
			// styles par défaut du curseur
			$curseur.css({
				position : "relative",
				width : 10,
				backgroundColor : "#4CC",
				cursor : "pointer"
			});

			// si le bloc a de besoin d'un scroll
			if($contenu.outerHeight() <= $conteneur.outerHeight()){
				if($(this).find(".barreSlide").length){
					$(this).find(".barreSlide").remove();
				}
				debugScroll("pas assez de contenu : "+$contenu.outerHeight() +" <= " + $conteneur.outerHeight());
				return true;
			}

			$conteneur.append($barre);
			setHauteurCurseur();
			setWheelStep();
			setArrowStep();

			curseurHeight = $curseur.outerHeight();
			barreHeight = $barre.outerHeight();
			contenuHeight = $contenu.outerHeight();

			// Défini la hauteur du curseur
			function setHauteurCurseur(){
				if(params.cursorHeight == null){
					return;
				}else if(params.cursorHeight == "auto"){
					var hauteurCurseur = $barre.outerHeight() / $contenu.outerHeight() * $barre.outerHeight();
					$curseur.css("height", hauteurCurseur);
				}else{
					$curseur.css("height", params.cursorHeight)
				}
			}

			// Défini la vitesse de scroll
			function setWheelStep(){
				if(params.wheelStep == "auto"){
					wheelStep = $barre.outerHeight() / $contenu.outerHeight() * 12;
				}
			}

			// Défini la vitesse lors de l'appel de scrollUp et scrollDown
			function setArrowStep(){
				if(params.arrowStep == "auto"){
					params.arrowStep = 3;
				}
			}

			// Débute l'interval de déplacement
			function startDragCurseur(e){
				var posRelativeTop = ($.browser.msie)? e.offsetY : e.layerY;
				offsetY = $conteneur.offset().top + posRelativeTop - curseurHeight / 2;
				intervalDrag = setInterval(dragCurseur, params.updateTime);
				$curseur.addClass("drag");
				e.preventDefault();
			}

			// Stop l'interval de déplacement
			function stopDragCurseur(e){
				clearInterval(intervalDrag);
				$curseur.removeClass("drag");
			}

			// Update de la position lorsque le drag est actif (appelé en interval)
			function dragCurseur(){
				var currentY = $document.data("currentMouseY") - curseurHeight / 2 - offsetY;
				if(currentY < 0) currentY = 0;
				if(currentY > barreHeight - curseurHeight) currentY = barreHeight - curseurHeight;
				
				$curseur.css("top", currentY);
				scrollContentPercent(currentY / (barreHeight - curseurHeight));
			}
			
			// force le déplacement du curseur à un pourcentage
			function curseurToPourcentage(percent){
				var currentY = (barreHeight - curseurHeight) * percent;
				if(currentY != undefined){
					$curseur.css("top", currentY);
				}
			}

			// Scroll le contenu selon le pourtantage (0:1)
			function scrollContentPercent(percent){
				pourcentage = percent;
				if(percent != undefined){
					var toY = -percent * (contenuHeight - barreHeight);
					
					// si le contenu a bougé (pas une répétition sans mouvement)
					if(toY != currentContentY){
						$contenu.css("top", toY);
						currentContentY = toY;
					}
				}
			}

			// Lors d'un event mousewheel sur contenu
			function mouseWheelConteneur(e, delta){
				pourcentage += (-delta * 0.01) * wheelStep;
				if(pourcentage < 0) pourcentage = 0;
				else if(pourcentage > 1) pourcentage = 1;
				scrollContentPercent(pourcentage);
				curseurToPourcentage(pourcentage);
				e.preventDefault();
			}

			// Scroll le contenu vers le haut selon params.arrowStep
			function scrollUp(){
				pourcentage += params.arrowStep;
				if(pourcentage > 1) pourcentage = 1;
				scrollContentPercent(pourcentage);
			}

			// Scroll le contenu vers le bas selon params.arrowStep
			function scrollDown(){
				pourcentage -= params.arrowStep;
				if(pourcentage < 0) pourcentage = 0;
				scrollContentPercent(pourcentage);
			}
		});

		// Lors d'un mousemove, on stock la position dans le document
		function documentMouseMove(e){
			$document.data("currentMouseX", e.pageX);
			$document.data("currentMouseY", e.pageY);
		}
		
		function debugScroll(txt){
			if(params.debug && console && console.log){
				console.log(txt);
			}
		}
	}

}) (jQuery);



