/**
* jQuery Slideshow
* Author: Savut Sang
*
* Usage:
* Ex: jQuery("#slides").slideshow();
* Ex: jQuery("#slides").slideshow( {'speed': 300, 'auto': false, 'transition' : 'slideUp'} );
* Ex: jQuery("#slides").slideshow( {'speed': 900} );
*
* Pause animation:  jQuery("#slides").slideshow( "pause" );
* Resume animation: jQuery("#slides").slideshow( "resume" );
*
* Change default values for all instance:
* ex: jQuery.slideshow.defaults.speed = 900;
* ex: jQuery.slideshow.defaults.auto = false;
*
* FYI: $e represente tous le temps une instance individuel des selectors, donc equivalent du $(this) dans le each() loop.
* FYI: $t represente tous le temps les tabs du container current.
* FYI: $s represente tous le temps les slides du container current.
*/
(function($) {
    var SlideshowApi = function($e, opts){
        this.container = $e;
        this.options = opts;
        this.elements = {
            tabs: $e.find(opts.tabsSelector),
            slides: $e.find(opts.slidesSelector)
        };

        $.extend(this.options, {
            timer: null,
            items: null,
            currentIndex: 0,
            countSlides: $e.find(opts.slidesSelector).find(">li").length,
            slideHeight: $e.find(opts.slidesSelector).find(">li:first").outerHeight(),
            slideWidth: $e.find(opts.slidesSelector).find(">li:first").outerWidth()
        });
    }

    SlideshowApi.prototype = {
        changeSlidePrev: function(){
            var opts = this.options;

            var nextIndex = opts.currentIndex - opts.step;

            if (opts.circular) {
                if (nextIndex < 0) {
                    nextIndex = opts.countSlides - 1;
                }
                this.changeSlide(nextIndex);
            } else {
                if (opts.currentIndex > 0) {
                    if (nextIndex < 0) {
                        nextIndex = 0;
                    }
                    this.changeSlide(nextIndex);
                    this.disabledOffsetNavigation();
                }
            }
        },

        changeSlideNext: function(){
            var opts = this.options;

            var nextIndex = opts.currentIndex + opts.step;

            if (opts.circular) {
                if (nextIndex >= opts.countSlides) {
                    nextIndex = 0;
                }
                this.changeSlide(nextIndex);
            } else {
                var lastVisibleOffset = opts.countSlides - opts.showItems;
                if (opts.currentIndex < lastVisibleOffset) {
                    if (nextIndex > lastVisibleOffset) {
                        nextIndex = lastVisibleOffset;
                    }
                    this.changeSlide(nextIndex);
                    this.disabledOffsetNavigation();
                }
            }
        },

        disabledOffsetNavigation: function(){
            if (this.elements.buttonPrev) {
                this.elements.buttonPrev.removeClass('slideshow-prev-disabled');

                if (this.options.currentIndex <= 0) {
                    this.elements.buttonPrev.addClass('slideshow-prev-disabled');
                }
            }

            if (this.elements.buttonNext) {
                this.elements.buttonNext.removeClass('slideshow-next-disabled');

                var lastVisibleOffset = this.options.countSlides - this.options.showItems;
                if (this.options.currentIndex >= lastVisibleOffset) {
                    this.elements.buttonNext.addClass('slideshow-next-disabled');
                }
            }
        },

        changeSlide: function(index){
            var opts = this.options;
            opts.currentIndex = index;

            var $t = this.elements.tabs;
            var $s = this.elements.slides;

            // Gestion des tabs et change le current index a celui qui est clique
            $t.find(">li").removeClass("active");
            $t.find(">li:eq("+index+")").addClass("active");

            var leftPosition;
            switch (opts.transition) {
                case 'slideUp':
                    var topPosition = opts.slideHeight * -1;

                    $s.append("<li>" + opts.items[index] + "</li>");
                    $s.animate({'top': topPosition}, opts.speed, function(){
                        $s.find(">li:first").remove();
                        $s.css('top', 0);
                    });
                    break;

                case 'slideLeft':
                    leftPosition = opts.slideWidth * -1;

                    $s.append("<li>" + opts.items[index] + "</li>");
                    $s.animate({'left': leftPosition}, opts.speed, function(){
                        $s.find(">li:first").remove();
                        $s.css('left', 0);
                    });
                    break;

                case 'slideRight':
                    leftPosition = 0;

                    $s.css('left', opts.slideWidth * -1);
                    $s.prepend("<li>" + opts.items[index] + "</li>");
                    $s.animate({'left': leftPosition}, opts.speed, function(){
                        $s.find(">li:last").remove();
                        $s.css('left', 0);
                    });
                    break;

                case 'slideHorizontal':
                    var pos = $s.find(">li:eq("+index+")").position();
                    leftPosition = pos.left * -1;
                    $s.width(opts.slideWidth * opts.countSlides);
                    $s.animate({'left': leftPosition}, opts.speed);
                    break;

                case 'fade':
                    $s.find("li:visible").fadeOut(opts.speed);
                    $s.find(">li:eq("+index+")").fadeIn(opts.speed);
                    break;
            }

            // restart the timer if auto (keep going)
            if (opts.auto == true) {
                this.startTimer();
            }
        },
        
        saveSlidesToItems: function(){
            var opts = this.options;
            var $e = this.container;

            opts.items = new Array;
            $e.find(".slideshow-slides > li").each(function(index){
                opts.items.push( $(this).html() );
                if (index != opts.startIndex) {
                    $(this).remove();
                }
            });
        },

        clearTimer: function(){
            clearTimeout(this.options.timer);
        },
        
        startTimer: function(){
            var $T = this;
            var opts = this.options;
            this.clearTimer(); // dans le cas ou il nous reste un timer en cour, on veut le clear parce on restart un nouveau.

            opts.timer = setTimeout(function(){
                $T.timerHit();
            }, opts.timeout);
        },

        timerHit: function(){
            this.changeSlideNext();
            this.startTimer();
        }
    };





    var $H = $.slideshow = {
        // default options
        defaults: {
            speed: 500,     /* (Integer) animation speed */
            auto: true,     /* [true|false] change slides automatically */
            timeout: 3000,  /* (Integer) milliseconds pour le auto scroll */
            transition: "fade",  /* ["slideUp"|"slideLeft"|"slideRight"|"slideHorizontal"|"fade"] */
            tabsSelector: ".slideshow-tabs",
            slidesSelector: ".slideshow-slides",
            startIndex: 0,
            circular: true,
            step: 1,        /* (Integer) number of items to slide at the time (use only for slideHorizontal for the moment) */
            showItems: 3,   /* (Integer) number of items to show at the time */
            navigation: false,
            navigationPrevButton: '&lt;',
            navigationNextButton: '&gt;'
        },

        buildHtml: function($e) {
            var api = $e.data('SlideshowApi');
            var opts = api.options;
            var $t = api.elements.tabs;
            var $s = api.elements.slides;

            /**
             * Ajoute les elements et les classes necessaire au bon fonctionnement du plugin
             */
            if ($(".slideshow-wrapper", $e).length == 0) {
                var $tempWrapper = $("<div />").addClass('slideshow-wrapper');
                $s.wrap($tempWrapper);
            }

            if (opts.navigation) {
                if ($('.slideshow-next', $e).length == 0) {
                    $e.prepend("<a class='slideshow-next'>"+ opts.navigationNextButton +"</a>");
                    api.elements.buttonNext = $e.find(".slideshow-next");
                }
                if ($('.slideshow-prev', $e).length == 0) {
                    $e.prepend("<a class='slideshow-prev'>"+ opts.navigationPrevButton +"</a>");
                    api.elements.buttonPrev = $e.find(".slideshow-prev");
                }
            }

            // Ajouter les classes
            if (!$e.hasClass("slideshow")) {$e.addClass("slideshow");}
            if (!$t.hasClass("slideshow-tabs")) {$t.addClass("slideshow-tabs");}
            if (!$s.hasClass("slideshow-slides")) {$s.addClass("slideshow-slides");}

            // Transition effect between slide
            switch (opts.transition) {
                case 'slideUp':    // circular
                    $s.addClass("slideshow-slides-vertical");
                    api.saveSlidesToItems();
                    break;
                case 'slideLeft': // circular
                    $s.addClass("slideshow-slides-horizontal");
                    $s.width( opts.slideWidth * 2 );
                    api.saveSlidesToItems();
                    break;
                case 'slideRight': // circular
                    $s.addClass("slideshow-slides-horizontal");
                    $s.width( opts.slideWidth * 2 );
                    api.saveSlidesToItems();
                    break;

                case 'slideHorizontal':    // non circular
                    $s.addClass("slideshow-slides-horizontal");
                    opts.circular = false;
                    $s.width( opts.slideWidth * opts.countSlides );
                    $s.css('left', opts.slideWidth * opts.startIndex * -1);
                    break;
                case 'fade': // circular
                    $s.addClass("slideshow-slides-absolute");
                    $s.find(">li:eq("+opts.startIndex+")").show();
                    break;
            }


        },

        bindEvents: function($e){
            var api = $e.data('SlideshowApi');

            // Ajoute les events pour les tabs, quand on click sur un tabs, ca affiche le content
            // et ca clear le timer automatic rotation
            var tabIndex = 0;
            api.elements.tabs.find(">li").unbind('click');
            api.elements.tabs.find(">li").each(function(){
                $(this)
                    .data("SlideshowTabIndex", tabIndex)
                    .click(function(){
                        api.changeSlide($(this).data("SlideshowTabIndex"));
                    });
                tabIndex++;
            });

            
            if (api.elements.buttonNext) {
                api.elements.buttonNext.unbind('click.slideshow');
                api.elements.buttonNext.bind('click.slideshow', function(){
                    api.changeSlideNext();
                });
            }
            if (api.elements.buttonPrev) {
                api.elements.buttonPrev.unbind('click.slideshow');
                api.elements.buttonPrev.bind('click.slideshow', function(){
                    api.changeSlidePrev();
                });
            }
        }
    }
    

    /**
     * params peut etre un objet pour l'initialisation
     * ou un string pour une commande
     */
    $.fn.slideshow = function(params) {
        if (typeof params == 'string') {
            if (params == "api") {
                return $(this).data('SlideshowApi');
            }

            // else
            return this.each(function() {
                var $e = $(this);
                var api = $e.data('SlideshowApi');

                switch (params) {
                    case "pause":
                        api.clearTimer();
                        break;
                    case "resume":
                        api.startTimer();
                        break;
                }
            });

        } else {

            // selector options
            return this.each(function() {
                var $e = $(this);

                // instance options
                var opts = $.extend({}, $H.defaults, params);
                
                var api = new SlideshowApi($e, opts);

                // On sauvegarde l'options dans l'objet mere, cela permet d'appeler encore l'objet et d'avoir access a ses options
                $e.data('SlideshowApi', api);

                $H.buildHtml($e);
                $H.bindEvents($e);


                /**
                 * Initial
                 */
                opts.currentIndex = opts.startIndex;
                
                var $w  = $(".slideshow-wrapper", $e);
                
                if ($w.width() == 0)  {$w.css('width', opts.slideWidth);}
                if ($w.height() == 0) {$w.css('height', opts.slideHeight);}

                api.elements.tabs.find(">li").removeClass("active");
                api.elements.tabs.find(">li:eq("+opts.currentIndex+")").addClass("active");
                api.disabledOffsetNavigation();

                // Demarre le timer pour Auto
                if (opts.auto == true) {
                    api.startTimer();
                }
            });

        }
    };

})(jQuery);
