(function($) {

    pluginName = 'slide';

	var dirLeft  = -1;
	var dirRight = 1;

    $.slide = function (el, options) {
        // To avoid scope issues, use 'base' instead of 'this'
        // to reference this class from internal events and functions.
        var base = this;
        
        // Access to jQuery and DOM versions of element
        base.$el = $(el);
        base.el = el;

        // Add a reverse reference to the DOM object
        base.$el.data("slide", base);

        base.init = function (options) {

            // mélange des paramètres fournis et des paramètres par défaut
            base.options = $.extend({}, $.slide.defaultOptions,options);

            base.slides      = base.options.slider.children();
            //log(base.slides.width());
            base.nbSlides    = base.slides.size();
            base.slideWidth  = parseInt(base.slides.innerWidth());
            base.slideHeight = parseInt(base.slides.innerHeight());
            base.sliderWidth = base.slideWidth * base.nbSlides;
            base.indexOn     = 0;
            base.indexPrev   = null;
            base.indexMin    = 0;
            base.indexMax    = base.nbSlides-1;
            base.indexToGo   = null;

            /**Initialisation du module**/
            base.options.container.css({height: base.slideHeight+'px'});

            switch (base.options.effect) {
                case 'slide' :
                    base.options.container.css({overflow: 'hidden'});
                    base.options.slider.css({
                        width      : base.sliderWidth,
                        height     : base.options.container.height(),
                        marginLeft : '0'
                    });
                    base.slides.css({float: 'left', position: 'relative'});
                    //log(base.slides.width());

                    break;
                case 'fade' :
                    base.options.slider.css({ position: 'relative' });
                    base.slides.each(function () {
                        $(this).css({position: 'absolute', top:0, left:0});
                        if ($(this).index() != 0) {
                            $(this).hide();
                            //$(this).remove();
                            //$(this).prependTo(base.options.slider);
                        } else {
                            $(this).show();
                        }
                    });

                    break;
            }
            
            //En cas de boucle
            if (base.options.loop && base.options.effect == 'slide') {
                var lastSlide = base.slides.last();

                base.options.slider.css('marginLeft',base.getSliderPosition()-base.slideWidth+'px');
                //lastSlide.remove();
                base.options.slider.prepend(lastSlide);
            }

            //Création des liens cliquables
            if (base.options.links) {
                if (!base.options.noactiv) base.setActivLink();

                var links = base.options.links.find('a');
                links.unbind('click').bind('click',function () {

                    base.goTo(links.index($(this)));

                    return false;
                });
            }

            //base.initDirection();
            base.initAuto();
        };
        
		/**
		 * Function initAuto 
		 * 
		 * @description : Lance l'animation automatique et clear le timer si besoin
		 * @access : public
		 * @return : void
		 * @date : 2010-06-04
		 * @author : François Guémard <f.guemard@hegyd.com>
		 */
		base.initAuto = function() {
			if (base.options.auto) {
				if (base.timer != '') clearInterval(base.timer);

				base.timer = window.setInterval(function () { base.move(); }, base.options.delay);
			}
		}

		/**
		 * Function initDirection 
		 * 
		 * @description : Initialise la direction à prendre 
		 * @access : public
		 * @return : void
		 * @date : 2010-06-04
		 * @author : François Guémard <f.guemard@hegyd.com>
		base.initDirection = function() {
			if (base.indexToGo != null) {
				if (base.indexToGo < base.indexOn) {
					base.options.direction = dirLeft;
				} else if (base.indexToGo > base.indexOn) {
					base.options.direction = dirRight;
				} else if (base.indexToGo == base.indexOn) return false;
			}
		}
		 */

		/**
		 * Function move 
		 * 
		 * @description : Fonction gérant le lancement de l'animation
		 * @access : public
		 * @return : void
		 * @date : 2010-06-01
		 * @author : François Guémard <f.guemard@hegyd.com>
		 */
		base.move = function() {

            if (base.locked) return false;

			if (base.slides.length <= 1) return false;

			switch (base.options.effect) {
				case 'slide' : base.slide(); break;
				case 'fade'  : base.fade(); break;
			}

			base.updateIndexPrev();
			base.updateIndexOn();
			base.updateDirection();

			base.setActivLink();
			base.resetIndexToGo();
		}

		/**
		 * Function slide 
		 * 
		 * @description : Effectue le slide du slider 
		 * @access : public
		 * @return : void
		 * @date : 2010-06-01
		 * @author : François Guémard <f.guemard@hegyd.com>
		 */
		base.slide = function() {
			var posToGo   = base.getPosToGo();
			var slideToGo = '';
			var prevSlide = '';

			if (base.options.loop) {
				if (base.options.direction == dirRight) {
					var firstSlide = base.slides.first();
					
					base.options.slider.css('marginLeft',(base.getSliderPosition()+base.slideWidth)+'px');
					//firstSlide.remove();
					base.options.slider.append(firstSlide);
				} else if (base.options.direction == dirLeft) {
					var lastSlide = base.slides.last();

					base.options.slider.css('marginLeft',(base.getSliderPosition()-base.slideWidth)+'px');
					//lastSlide.remove();
					base.options.slider.prepend(lastSlide);
				}

				base.slides = base.options.slider.children();
			}

			//Effectuer le slide en fonction de la direction et du positionnement du slide
			if (base.options.direction == dirRight && base.indexOn >= base.indexMin && base.indexOn < base.indexMax) {
				base.options.slider.stop().animate({
					marginLeft: posToGo+'px'
				},base.options.effectSpeed,base.options.easing);
			} else if (base.options.direction == dirLeft && base.indexOn <= base.indexMax && base.indexOn > base.indexMin) {
				base.options.slider.stop().animate({
					marginLeft: posToGo+'px'
				},base.options.effectSpeed,base.options.easing);
			}

			if (base.options.loop) {
				base.indexOn = 0;
			}
		}

		/**
		 * Function fade 
		 * 
		 * @description : Effectue le fadeIn / fadeOut des slides
		 * @access : public
		 * @return : void
		 * @date : 2010-06-01
		 * @author : François Guémard <f.guemard@hegyd.com>
		 */
		base.fade = function() {
			var slideToMove = '';
			var prevSlide   = '';
			var indexToMove = base.getIndexToMove();

			base.prevFade();

			if (base.options.loop
                || (base.options.direction == dirRight && base.indexOn >= base.indexMin && base.indexOn < base.indexMax)
                || (base.options.direction == dirLeft && base.indexOn <= base.indexMax && base.indexOn > base.indexMin)) {
				slideToMove = base.slides.eq(indexToMove);
				prevSlide   = base.slides.eq(base.indexOn);

                if (slideToMove.is(':animated') || prevSlide.is(':animated')) return false;

				slideToMove.fadeIn(base.options.effectSpeed);
				prevSlide.fadeOut(base.options.effectSpeed);
			}
		}

		base.prevFade = function() {
			if (base.indexPrev != null) {
				base.slides.each(function (index) {
					if (index != base.indexOn) {
						$(this).hide();
						//$(this).remove();
						//$(this).prependTo(base.options.slider);
					}
				});
			}
		}

		/**
		 * Function resetActivLink 
		 * 
		 * @description : Supprime la class activ de tous les liens
		 * @access : public
		 * @return : void
		 * @date : 2010-06-01
		 * @author : François Guémard <f.guemard@hegyd.com>
		 */
		base.resetActivLink = function() {
			if (base.options.links && !base.options.noactiv)
				base.options.links.find('a').removeClass('activ');
		}

		/**
		 * Function resetIndexToGo 
		 * 
		 * @description : Remet l'indexToGo à null
		 * @access : public
		 * @return : void
		 * @date : 2010-06-04
		 * @author : François Guémard <f.guemard@hegyd.com>
		 */
		base.resetIndexToGo = function() {
			base.indexToGo = null;
		}


		/**
		 * Function updateDirection 
		 * 
		 * @description : Met à jour la direction à prendre en fonction des limites atteintes
		 * @access : public
		 * @return : void
		 * @date : 2010-06-04
		 * @author : François Guémard <f.guemard@hegyd.com>
		 */
		base.updateDirection = function() {
            if (base.options.loop) return false;
			if (base.options.direction == dirRight && base.indexOn == base.indexMax) base.options.direction = dirLeft;
			else if (base.options.direction == dirLeft && base.indexOn == base.indexMin) base.options.direction = dirRight;
		}

		/**
		 * Function updateIndexOn 
		 * 
		 * @description : Met à jour l'indexOn suivant le slide affiché
		 * @access : public
		 * @return : void
		 * @date : 2010-06-04
		 * @author : François Guémard <f.guemard@hegyd.com>
		 */
		base.updateIndexOn = function() {
			if (base.indexToGo != null) base.indexOn = base.indexToGo;
			else {
				if (base.options.direction == dirRight) base.indexOn+=1;
				else if (base.options.direction == dirLeft) base.indexOn-=1;
			}
            if (base.indexOn < 0 || base.indexOn > base.indexMax) base.indexOn = 0;
		}

		/**
		 * Function updateIndexPrev 
		 * 
		 * @description : Met à jour l'indexPrev
		 * @access : public
		 * @return : void
		 * @date : 2010-06-04
		 * @author : François Guémard <f.guemard@hegyd.com>
		 */
		base.updateIndexPrev = function() {
			base.indexPrev = base.indexOn;
		}

		/**
		 * Getters & Setters 
		 */

		/**
		 * Function getIndexToMove 
		 * 
		 * @description : Calcul l'index à afficher 
		 * @access : public
		 * @return : void
		 * @date : 2010-06-04
		 * @author : François Guémard <f.guemard@hegyd.com>
		 */
		base.getIndexToMove = function() {
			var indexToMove = false;

			if (base.indexToGo != null)
				indexToMove = base.indexToGo;
			else {
				if (base.options.direction == dirRight)
					indexToMove = base.indexOn+1;
				else if (base.options.direction == dirLeft)
					indexToMove = base.indexOn-1;
			}

            if (indexToMove < 0 || indexToMove > base.indexMax) indexToMove = 0;

			return indexToMove;
		}

		/**
		 * Function getPosToGo 
		 * 
		 * @description : Calcule la position à adopter pour le slide
		 * @access : public
		 * @return : void
		 * @date : 2010-06-04
		 * @author : François Guémard <f.guemard@hegyd.com>
		 */
	    base.getPosToGo = function() {
			var sliderPos = base.getSliderPosition();
			var posToGo = false;

			if (base.options.loop) {
				sliderPos = 0;

				if (base.options.direction == dirRight) base.slideWidth = (base.slides.eq(base.indexOn-1).innerWidth());
				else if (base.options.direction == dirLeft) base.slideWidth = (base.slides.eq(base.indexOn).innerWidth());
			}

			if (base.indexToGo != null) {
				posToGo = -(base.indexToGo*base.slideWidth);
			} else {
				if (base.options.direction == dirRight) posToGo = sliderPos-base.slideWidth;
				else if (base.options.direction == dirLeft) posToGo = sliderPos+base.slideWidth;
			}

			return posToGo;
		}

		/**
		 * Function getSliderPosition
		 * 
		 * @description : 
		 * @access : public
		 * @return : void
		 * @date : 2010-06-01
		 * @author : François Guémard <f.guemard@hegyd.com>
		 */
		base.getSliderPosition = function() {
			return parseInt(base.options.slider.css('marginLeft'));
		}

		/**
		 * Function setActivLink 
		 * 
		 * @description : Modifie les liens pour leur affecter la classe activ
		 * @access : public
		 * @return : void
		 * @date : 2010-06-01
		 * @author : François Guémard <f.guemard@hegyd.com>
		 */
		base.setActivLink = function() {
			base.resetActivLink();
			if (base.options.links && !base.options.noactiv) {
				base.options.links.find('a').eq(base.indexOn).addClass('activ');
			}
		}

        base.goFirst = function() {
            base.goTo(0);
        }

        base.goLast = function() {
            base.goTo(base.nbSlides-1);
        }

        base.goTo = function(index) {
            base.indexToGo = index;

            base.initAuto();//Met à jour le timer
            if (base.indexToGo != base.indexOn) base.move();//Lance l'animation si le slide a afficher n'est pas celui en cours
        }

        base.attach = function(elem, index) {
            elem.appendTo(base.options.slider);
            var lastLink = base.options.links.find('a:last');
            var newLink  = lastLink.clone();
            lastLink.after(newLink);

            base.options.direction = dirRight;
            base.init(base.options);

        }

        base.detach = function(index) {
            base.options.slider.children().eq(index).remove();
            base.options.links.find('a').eq(index).remove();
            base.options.direction = dirRight;
            base.init(base.options);
        }

        base.lock = function() {
            base.locked = true;
        }

        base.unlock = function() {
            base.locked = false;
        }
    };

    $.slide.defaultOptions = {
			container : '',
			slider    : '',
			links     : '',
			way       : 'horizontal',
			direction : dirRight,//-1 <-, 1 ->
			effect    : 'slide',
			easing    : 'easeInOutCubic',
			effectSpeed : 'normal',
			auto      : true,
			loop      : false,
			delay     : 5000,
			timer     : '',
			noactiv   : false//Paramètre court-circuit qui à true permet de ne pas modifier la class des liens
    };

	$.fn.slide = function (method) {

		// récupération des arguments et nom de la methode 
		var methodArguments = arguments;
		var methodName = method;

		// obtain property value 
		if(methodName == 'property' && arguments[1] && this[0]){
			var property = arguments[1];
			if( !(plugin = $(this[0]).data(pluginName)) ){
				plugin = new $.slide(this[0]);
			}
			if(plugin[property]){
				return plugin[property];
			}else{
				return null;
			}
		}
	
		// method and initialisation 
		return this.each(function(){
			// si le plugin n'est pas encore associé à l'objet , l'associé 
			if( !(plugin = $(this).data(pluginName)) ){
				plugin = new $.slide(this);
			}
		
			// si methodName correspond à une méthode 
			if( plugin[methodName] ){
				methodArguments = Array.prototype.slice.call( methodArguments, 1 )
			// sinon si c'est un objet ou rien de passé , faire methode init 
			}else if( typeof method === 'object' || !method){
				methodName = 'init';
			}else {
				return log('ERROR');
			}	
			return plugin[methodName].apply( this, methodArguments);
		});

	};

    // This function breaks the chain, but returns
    // the slide if it has been attached to the object.
    $.fn.getSlide = function(){
        $(this).data("slide");
    };

})(jQuery);

