
 /* 
	 * Définition de Marquee, fonction de défilement 
	 * @param box (string/node) le noeud marquee 
	 * @param options (map) les options
	 *		- speed : la vitesse du déplacement (default 0.5)
	 *		- dirc : la direction du déplacement (default top)
	 *		- btSpeedUp : la bouton d'accélération 
	 *		- btSpeedDown : la bouton d'esaccélération 
	 *		- speedActiveBt : vitesse d'accélaration pour le bouton (default 10)
	 *		- cssActiveBtSpeedUp : class du bouton accélération actif
	 *		- cssActiveBtSpeedUp : class du bouton desaccélération actif
	 *		- eventBt : l'évenement de l'activation de bouton (default over, sinon down)
	 *		- stopOnOver : pour stopper le difelement au survole (default false)
	 *		- scrollOnMove : pour actievr le scrolling au survole
	 *		- maxSpeedOnMove : vitesse d'accélaration pour le scrool (default 10)
	 *		- expoSpeedOnMove : comportement exponentiel de l'accélaration  (default 2)
	 *		- draggable : permet de scroller le contenue lors d'un drag  (default false)
	 *		- cursorOverDrag : définit l'url du curseur à utilisé pour spécifié que le contenue peux etre "dragger" 
	 *		- cursorOnDrag : définit l'url du curseur à utilisé pour spécifié que le contenue est en train d'etre "dragger" 
	 */
var Marquee = (function($){

	var Cookie = {
	    read : function(name){
			var i = document.cookie.indexOf(name + "=");
			if (i > -1) {
				i += name.length + 1
				var j = document.cookie.indexOf(';', i);
				if (j < 0) 
				    j = document.cookie.length;
				return unescape(document.cookie.substring(i, j));
			}
			return '';
		},
		write : function(name, value){
		    document.cookie = name + "=" + escape(value);
		}
	};
	
    var extendIf = function(destination, source){
	    for (var property in source)
			if(destination[property] === undefined)
				destination[property] = source[property];
		return destination;
	};
	/*------Liaison des contextes d'éxecution des fonctions aux objets-------------------------*/
	/*
	* Jquery possède la méthode proxy depuis là 1.4, mais on peux pas lui passer d'arguments....
	*/
	var bind = function(__method){
		var  args = Array.prototype.slice.call(arguments, 1), object = args.shift();
		return function(event) {
		    return __method.apply(object, args.concat(Array.prototype.slice.call(arguments,0)));
		}
	};
	
	/*------Laison des contextes d'éxecution des fonctions aux objets , avec en 1er argument un événement-------------------------*/
	
	var bindAsEventListener = function(__method){
		var args = Array.prototype.slice.call(arguments, 1), object = args.shift();
		return function(event) {
		    return __method.apply(object, [( event || window.event)].concat(args));
		}
	};
	
	
    var Marquee = function(box, options){
	    this.box = box;
		this.content = this.box[0].firstChild.nodeType == 1 ? this.box[0].firstChild : this.box[0].childNodes[1];//j'arrive pas à récupérer le premier enfant autrement children() marche pas...
		this.coefDirc = 1;
		
		//ini les options
		this.options = extendIf(options || {}, this.options);
		if(typeof this.options.btSpeedUp == 'string')
		    this.options.btSpeedUp = $('#' + this.options.btSpeedUp);
		if(typeof this.options.btSpeedDown == 'string')
		    this.options.btSpeedDown = $('#' + this.options.btSpeedDown);
		
		this._speed = this.options.speed;
		this.inverseDirc = this.options.dirc=='bottom' || this.options.dirc=='right';
		this.horizontalDirc = this.options.dirc=='bottom' || this.options.dirc=='top';		
		
		this.box.css('overflow','hidden');
		this.box.css('position','relative');
		this.content.style.position = 'absolute';
		
		//calcule la dimension du conteneur  + la dimention du contenue 
		var boxDim = box.get(0)['client' + (this.horizontalDirc ? 'Height' : 'Width')];
		var contentDim = this.content['offset' + (this.horizontalDirc ? 'Height' : 'Width')];
		
		//on definit las position max et min
		this.maxDim = -contentDim;
		this.startStep =  boxDim;
		
		if(this.options.activeCookie && this.box[0].id){
			 $(window).bind('unload', bindAsEventListener(this.saveCookie, this));
			 this.currentStep = this.getCookie() || this.startStep;
		}else{		
		    this.currentStep = this.startStep;
		}
		
		
		if(this.options.btSpeedUp || this.options.btSpeedDown){
		    this.eventsBt = this.options.eventBt == 'over' ? ['mouseover', 'mouseout'] : ['mousedown', 'mouseup'];
		}
		//ajoutes les evenemnts du bouton speedUp
		if(this.options.btSpeedUp){
		    this.options.btSpeedUp.bind(this.eventsBt[0] , bindAsEventListener(this.onActiveBt, this, this.inverseDirc));
			//this.options.btSpeedUp.bind(this.eventsBt[1],  bindAsEventListener(this.onInactiveBt, this));
		}
		
		//ajoutes les evenemnts du bouton speedDown
		if(this.options.btSpeedDown){
			this.options.btSpeedDown.bind(this.eventsBt[0],  bindAsEventListener(this.onActiveBt, this, !this.inverseDirc, true));
			//this.options.btSpeedDown.bind(this.eventsBt[1],bindAsEventListener(this.onInactiveBt, this, true));
		}
		
		//ajoutes l' evenemnt stopOnOver
		if(this.options.stopOnOver){
			this.box.bind('mouseover', bindAsEventListener(this.onMouseOverContent, this));
			this.box.bind('mouseout', bindAsEventListener(this.onMouseOutContent, this));
		}
		
		if(this.options.scrollOnMove){
		    this.middleDim = boxDim / 2;
			this.timeOut = false;
			 
			this.box.bind('mouseover', bindAsEventListener(this.onActiveScroll, this));
			this.box.bind('mouseout', bindAsEventListener(this.onInactiveScroll, this));
			this.box.bind('mousemove', bindAsEventListener(this.scrollOnMove, this));
		}
		
		if(this.options.draggable){
		    if(this.options.cursorOverDrag){
				this.box.bind('mouseover', bindAsEventListener(this.setCursorOverDrag, this));
				this.box.bind('mouseout', bindAsEventListener(this.setCursorOverDrag, this, true));
			}
			this.box.bind('mousedown', bindAsEventListener(this.onActiveDrag, this));
		}
		
		this.setInterval();
	}
	
	Marquee.prototype = {
	    options : {
		    speed : 0.5,
			speedActiveBt : 10,
			dirc : 'top',
		    eventBt : 'over',
			stopOnOver : false,
			maxSpeedOnMove : 10,
			expoSpeedOnMove : 2
		},
		
		onInactiveBt : function(e, down){
			this.options.speed = this._speed;
			var css = this.options['cssActiveBtSpeed' + (down ? 'Down' : 'Up')];
			if(css)
				this.options['btSpeed' + (down ? 'Down' : 'Up')].removeClass(css);
			
			this.toogleSelect(e, true);
			$(document).unbind(this.eventsBt[1], this['handlerInctiveBt' + (down ? 'Down' : 'Up')]);
		},
		
		onActiveBt : function(e, inverse, down){
			this.options.speed  = inverse ? -this.options.speedActiveBt : this.options.speedActiveBt;
			var css = this.options['cssActiveBtSpeed' + (down ? 'Down' : 'Up')];
			if(css)
			    this.options['btSpeed' + (down ? 'Down' : 'Up')].addClass(css);
			
			var eventHandler = 'handlerInctiveBt' + (down ? 'Down' : 'Up');
 			
		    this[eventHandler] = bindAsEventListener(this.onInactiveBt, this, down);
			$(document).bind(this.eventsBt[1], this[eventHandler]);
			this.toogleSelect(e);
		},
   
		onMouseOverContent : function(){
			this.clearInterval();
		},
		
		onMouseOutContent  : function(){
		    if(!this.isOndrag)
			    this.setInterval();
		},
		
		onActiveScroll : function(e){
		    //on passe par un setTimeout , pour eviter une émulation de mouseenter, mouseleave
			if(this.timeOut){
                clearTimeout(this.timeOut);
            }else{
                var dim = this.box.offset();
			    this.coor = this.options.dirc == 'top' || this.options.dirc == 'bottom' ? dim.top : dim.left;
				
            }
		},
		
		onInactiveScroll : function(e){
		    //on passe par un setTimeout , pour eviter une émulation de mouseenter, mouseleave
		    this.timeOut = setTimeout(bind(function(){
                this.timeOut = null;
				this.options.speed = this._speed;
            }, this), 0);

		},
		
		scrollOnMove : function(e){
		    if(this.options.dirc == 'top' || this.options.dirc == 'bottom'){
				var mouseCoor = e.pageY; 
			}else var mouseCoor = e.pageX;
			
			var ratio = (this.middleDim - (mouseCoor - this.coor))/ this.middleDim,
			coefDirc = Math.pow(ratio, this.options.expoSpeedOnMove) * this.options.maxSpeedOnMove;
			
			this.options.speed = (ratio > 0 ? coefDirc : coefDirc > 0 ? -coefDirc : coefDirc) * (this.inverseDirc ? -1 : 1);
		},
		
		onActiveDrag : function(e){
		    this.isOndrag = true;
			this.clearInterval();
			
		    this.coor = this.horizontalDirc ? e.pageY : e.pageX;
			 
			this.handlerInactiveDrag = bindAsEventListener(this.onInactiveDrag, this);
			$(document).bind('mouseup', this.handlerInactiveDrag);
			
			this.handlerDragOnMove = bindAsEventListener(this.dragOnMove, this);
			$(document).bind('mousemove', this.handlerDragOnMove);
			
			if(this.options.cursorOnDrag)
			    document.documentElement.style.cursor = 'url(' + this.options.cursorOnDrag + '), auto';
			
			this.toogleSelect(e);
			
		},
		
		onInactiveDrag : function(e){
		    this.isOndrag = false;
			var coor = this.horizontalDirc ? e.pageY : e.pageX;
			this.currentStep = this.inverseDirc ? this.currentStep - (coor - this.coor) : this.currentStep + (coor - this.coor) ;
			
			
			if(this.isOutDrag && this.options.cursorOnDrag){
			    document.documentElement.style.cursor = 'auto';
			}else if(this.options.cursorOverDrag){
			    document.documentElement.style.cursor = 'url(' + this.options.cursorOverDrag + '), auto';
			}
			
		    $(document).unbind('mouseup', this.handlerInactiveDrag);
			$(document).unbind('mousemove', this.handlerDragOnMove);
			
			this.toogleSelect(e, true);
			this.setInterval();
		},
		
		dragOnMove : function(e){
		    var coor = this.horizontalDirc ? e.pageY : e.pageX,
			steep =  this.inverseDirc ? this.currentStep - (coor - this.coor) : this.currentStep + (coor - this.coor) ;
			
			this.content.style[this.options.dirc] =  steep + 'px';
			
			if(steep > this.startStep){
				this.currentStep = this.maxDim;
				this.coor = coor;
			}else if(steep < this.maxDim){
			   this.currentStep = this.startStep;
				this.coor = coor;
			}
		},
		
		setCursorOverDrag : function(e, del){
		    if(!this.isOndrag){
		        document.documentElement.style.cursor = del ? 'auto' : 'url(' + this.options.cursorOverDrag + '), auto';
			}else this.isOutDrag = del;
		},
		
		setSteep : function(){
		    var acc = this.options.speed;
			this.content.style[this.options.dirc] = this.currentStep - acc + 'px';
			
			this.currentStep -= acc;
			if(this.currentStep > this.startStep){
				this.currentStep = this.maxDim;
			}else if(this.currentStep < this.maxDim){
			   this.currentStep = this.startStep;
			}
		},
		
		setInterval : function(){
		    if(!this.interval)
			    this.interval = setInterval(bind(this.setSteep, this), 35);
		},
		
		clearInterval : function(){
		    if(this.interval){
			    clearInterval(this.interval);
				this.interval = null;
			}
		},
		
		toogleSelect : function(e, enable){
		    if(enable){
			    document.onselectstart = null;
				document.ondragstart = null;
			}else{
			    document.onselectstart = function(){return false;};
				document.ondragstart = function(){return false;};
				e.preventDefault();
			}
		},
		getCookie : function(){
			return Cookie.read('marquee_'+this.box[0].id);
		},
		saveCookie : function(){
			Cookie.write('marquee_'+this.box[0].id, this.currentStep);
		}
	};
	
    
    $.fn.marquee = function(options){
	    return new Marquee(this, options);
	};
})(jQuery);





