

/**
 * Based on innerfade.js by Torsten Baldes http://medienfreunde.com
 * 
 * author Arjay Aquino
 * 
 * This Plugin adds callbacks and a Widget-like plugin architecture to the existing innerfade.js
 * Other features: Ability to pause slideshow when user hovers on slide, and can auto rotate the slides 
 * how ever many times it is set to, set which slide should show first.
 * 
 * Sample Usage with Callbacks:
 *      $('#slideshowCont').slideshow({
 *          speed             : 1400,
 *          timeout           : 6000,
 *          type              : 'sequence',
 *          containerheight   : 'auto',
 *          autoRotate        : true,
 *          firstSlide        : 0, //which slide index will show first
 *          maxRotateCount    : 0, //how many times the slide show will auto rotate. 0 is infinite
 *          pauseOnHover      : false, //if true, the slideshow will pause if mouse hovers on slideshow
 *          pauseOnNavClick   : false, //if true, the slideshow will pause once you click on the slide show nav
 *          slideDesc         : 'banner-desc',
 *          slideshowNav      : 'banner-menu',
 *          slideChangeStart  : function(args){ onSlideChangeStart(args); }, //called when slide is called to show
 *          slideChangeEnd    : function(args){ onSlideChangeEnd(args); }    //called when slide is done showing
 *      });
 * 
 * Each call back passes in an args object. The object keys are: slideID, cause, tagName, count
 * 
 * To call a public function for this plugin do this:
 *      $("elementname").data("SlideShow").publicMethod(args);
 * 
 * Public Methods:
 *      togglePause();
 *      setHoverOnPause(true or false); If true, tells the slideshow to pause if user hovers over the slide.
 */

(function($){
    
/**
 * PLUGIN CONSTRUCTOR
 */
    $.fn.slideshow = function(options){
        
        return this.each(function(){
            new SlideShow(this, options);
        });
    }

    
/**
 * PLUGIN CLASS
 * 
 * This plugin uses a Class pattern. An instance of this class will be attached to the HTML Element which 
 * allows for calling public methods on a specific INSTANCE.
 * 
 * init() method is called on SlideShow creation.
 */
    var SlideShow = function(element, options){
        
        var PLUGIN_NAME    = "SlideShow";
        
        element            = $(element);
        element.data(PLUGIN_NAME, this); //store reference to SlideShow object in the element
        
        var counter        = 0; //keeps track of how many times the slides have reached the end
        var isPlaying      = false; //play state
        var currentSlideID;    //reference to slide that needs to show
        var oldSlideID;        //reference to slide that needs to hide
        var changeCause    = "Auto"; //what causes the slides to change.. 
                                       //can be 'Click' for clicking on the nav or 'Auto' for auto rotation
        
        var options, slideList, slideDescList, slideThumbList, slideInterval;

        var originalSlideHeight;
        
        
    /**
     * PUBLIC METHODS
     */
        this.togglePause = function(){
            pausePlay();
            
        /*
         * added so that pause on hover doesnt toggle the slideshow to play when 
         * the slideshow has been paused intentionally by something else
         */
            if(isPlaying)
                options.pauseOnHover = true;
            else
                options.pauseOnHover = false;
        }
        
        this.setHoverOnPause = function(value){
            options.pauseOnHover = value; //true or false
        }
        
    
    /**
     * SLIDE SHOW
     */
        /**
         * Hide the slides and give them appropriate z index.
         * Show the first Slide.
         */
        var setUpSlideShow = function(){
            
            originalSlideHeight = $(slideList[0]).height();
            
            if(slideList.length > 1){
                for(var i=0; i<slideList.length; i++){
                    $(slideList[i])
                    .css('z-index', String(slideList.length-i))
                    .css('position', 'absolute')
                    .css('overflow', 'hidden')
                    .hide();
                    
                    if(options.slideDesc != null)
                        $(slideDescList[i]).css('z-index', String(slideDescList.length-i)).css('position', 'absolute').hide();
                }
            } else {
                $(slideList[0])
                    .css('z-index', 1)
                    .css('position', 'absolute')
                    .css('overflow', 'hidden');
                    
            }
            
            if(options.type == "sequence"){
                
                showFirstSlide();
                
                if(options.autoRotate && slideList.length > 1)
                    setUpTimer();
                
            }else{
                alert('Innerfade-Type must either be \'sequence\', \'random\' or \'random_start\'');
            }
        }
        
        
        /**
         * Display the first slide and its description.
         */
        var showFirstSlide = function(){
            
            $(slideList[currentSlideID]).show();
            $(slideList[currentSlideID]).siblings().animate({opacity:0}, 0).css("display", "list-item").height(1);
            if(options.slideDesc != null)
                $(slideDescList[currentSlideID]).show();
            
            if(options.slideShowNav != null){
                $("#"+options.slideShowNav+" li").removeClass("button-selected");
                $("#"+options.slideShowNav+" .slide_"+currentSlideID).addClass("button-selected");
            }
        }
        
        
        /**
         * Shows the new slide using the updated ids.
         * Hide the old slide before showing the new one.
         */
        var showSlide = function(){
            
            switch(options.animationtype){
                case "fade":
                    //fade out the old slide before fading in the new one
                        initiateCallBack("start");
                        $(slideList[oldSlideID]).animate({opacity:0}, options.speed);
                        if(options.slideDesc != null)
                            $(slideDescList[oldSlideID]).fadeOut(options.speed);
                        
                    //fade in the new slide
                        $(slideList[currentSlideID])
                        .height(originalSlideHeight)
                        .animate({opacity:1}, options.speed, function() {
                            removeFilter($(this)[0]);
                            initiateCallBack("end");
                            $(this).siblings().height(1);
                        });

                        if(options.slideDesc != null){
                            $(slideDescList[currentSlideID]).fadeIn(options.speed, function() {
                                removeFilter($(this)[0]);
                            });
                        }
                    break;//end fade
            }
        
        //update nav items
            if(options.slideShowNav != null){
                $("#"+options.slideShowNav+" li").removeClass("button-selected");
                $("#"+options.slideShowNav+" .slide_"+currentSlideID).addClass("button-selected");
            }
        }
        
        
        /**
         * Updates the current slide id and keeps a reference to the last id.
         * These will be used by showSlide method.
         */
        var nextSlide = function(){

            changeCause = "Auto";
            
            /*
             * if it is not at the end, show the next one otherwise show the first one
             * and keep a reference to the last id
             */ 
            if(currentSlideID < (slideList.length-1)){
                oldSlideID      = currentSlideID;
                currentSlideID += 1;
            }else{
                oldSlideID      = currentSlideID;
                currentSlideID  = 0;
                counter        += 1; //count everytime the slide reaches the end
            }
            
            //stop auto rotating if max rotate count is reached
            if(counter == options.maxRotateCount){
                stopTimer();
                options.autoRotate = false;
            }
            
            //show the slide using the updated ids
            showSlide();
        }
        
        
        var pausePlay = function(){
            
            //make sure it's set to auto rotate before toggling
            if(options.autoRotate && slideList.length > 1){
                if(isPlaying){
                    
                    if(options.slideShowPauseBTN != null){
                        $("#"+options.slideShowPauseBTN+" span").html("play");
                        $("#"+options.slideShowPauseBTN).attr("class", "paused_button");
                    }

                    stopTimer();
                    
                }else{
                    
                    if(options.slideShowPauseBTN != null){
                        $("#"+options.slideShowPauseBTN+" span").html("pause");
                        $("#"+options.slideShowPauseBTN).attr("class", "pause_button");
                    }
                    
                    setUpTimer(); //load next slide
                }
            }else{
                 stopTimer();
            }
        }
        
        
        /**
         * Attach a click event to the nav items and grab the id from them.
         */
        var setUpNavButtons  = function(){
            
            var buttonClass, splitButtonClassString, buttonClassString;
            
            $("#"+options.slideShowNav+" li").each(function(){
                
                $(this).css("cursor", "pointer");
                $(this).css("cursor", "hand");
                
                $(this).click(function(){
                    
                    //don't load the slide they are on
                    if($(this).hasClass("button-selected")){
                        return false;
                    }
                    
                    if(options.slideShowPauseBTN != null){
                        $("#"+options.slideShowPauseBTN+" span").html("play");
                        $("#"+options.slideShowPauseBTN).attr("class", "paused_button");
                    }
                    
                    buttonClass              = $(this).attr("class");
                    splitButtonClassString   = buttonClass.split("_");
                    buttonClassString        = splitButtonClassString.pop();
                    oldSlideID               = currentSlideID;
                    currentSlideID           = parseFloat(buttonClassString);
                    
                    changeCause = "Click";
                
                    
                    stopTimer();    //reset the timer

                //if pause on click is not on, start the timer again
                    if(!options.pauseOnNavClick && options.autoRotate){
                        setUpTimer();
                    }else{
                        options.autoRotate     = false; //turns off auto rotate
                    }
                         
                    showSlide();    //show new slide
                        
                });
                
            });//each
        }
        
        
        /**
         * If there's a pause button, attach click to it
         */
        var setUpPauseButton = function(){
            
            var pauseButton = $(options.slideShowPauseBTN);
            
            pauseButton.click(function(){
                togglePause();
            });
        }
        
        
        /**
         * If slide desc is available use that for the hover on pause,
         * otherwise use the slide itself.
         */
        var setUpPauseOnHover = function(){
            
            if(options.slideDesc != null){
                slideDescList.hover(function(){
                    if(options.pauseOnHover)
                        pausePlay();
                },
                //hover out
                function(){
                    if(options.pauseOnHover)
                        pausePlay();
                });
            }else{
                slideList.hover(function(){
                    if(options.pauseOnHover)
                        pausePlay();
                },
                //hover out
                function(){
                    if(options.pauseOnHover)
                        pausePlay();
                });
            }
        }
        
        /**
         * If slide thumbnail is available show it on hover
         */
        var setUpThumbnailOnHover = function(){         
            
            
            
            $("#"+options.slideShowNav+" li").each(function(){
                
                var name = "name="+$(this).attr('name');
                
                
                $(this).hover(function(){
                    
                    $("#"+options.slideShowThumbnail+" div["+name+"]").fadeIn("fast")
                },
                //hover out
                function(){
                    
                    $("#"+options.slideShowThumbnail+" div["+name+"]").fadeOut("fast")
                });
                
            });//each
        }
        
        
    /**
     * UTILS
     */
        var getDefaults = function(){
            
            return { animationtype     : 'fade',
                     speed             : 'normal',
                     type              : 'sequence',
                     timeout           : 5000,
                     containerheight   : 'auto',
                     autoRotate        : false,
                     firstSlide        : 0, 
                     maxLoopCount      : 0,
                     pauseOnHover      : false,
                     pauseOnNavClick   : false,
                     slideDesc         : null,
                     slideShowNav      : null,
                     slideShowPauseBTN : null,
                     slideChangeStart  : null,
                     slideChangeEnd    : null       
                  };
        }
        
        var setUpTimer = function(){
            isPlaying     = true;
            slideInterval = setInterval(nextSlide, options.timeout);
        }

        var stopTimer = function(){
            isPlaying         = false;
            
            if(slideInterval != null){
                clearInterval(slideInterval);
                slideInterval = null;
            }
        }
        
        /**
         * remove Opacity-Filter in ie
         */ 
        var removeFilter = function(target){
            if(target.style.removeAttribute){
                target.style.removeAttribute('filter');
            }
        }
        
        
        /**
         * Call the callback methods and pass in information so that it can be used by the listener.
         */
        var initiateCallBack = function(name){
            
            var slideTagName;
            
            /**
             * Grab the name of the slide from the nav items if there are any
             * otherwise use the id from the slide elements
             */
            if(options.slideShowNav != null){
                slideTagName = $('.slide_'+currentSlideID).attr("name");
            }else{
                slideTagName = $(slideList[currentSlideID]).attr("id");
            }
            
            var callbackArgs = { slideID   : currentSlideID,
                                 cause     : changeCause,
                                 tagName   : slideTagName,
                                 count     : counter
                               };
                
            switch(name){
                case "start":
                        $.isFunction( options.slideChangeStart ) && options.slideChangeStart.call(this, callbackArgs);
                    break;
                case "end":
                        $.isFunction( options.slideChangeEnd ) && options.slideChangeEnd.call(this, callbackArgs);
                    break;
            }
        }
        
        
    /**
     * INIT
     */
        var init = function(){
            
            var defaults   = getDefaults();
            options        = $.extend(defaults, options );
            
            element.css({ position :"relative", 
                          height : options.containerheight})
                   .addClass(PLUGIN_NAME);
            
            slideList      = element.children();
            
            currentSlideID = options.firstSlide;
            oldSlideID     = currentSlideID;
            
            if(options.slideDesc != null)
                slideDescList  = $("ul#"+options.slideDesc+" li");
            
            if(options.slideShowNav)
                setUpNavButtons();
            
            if(options.slideShowPauseBTN)
                setUpPauseButton();
            
            if(options.pauseOnHover)
                setUpPauseOnHover();
                
            if(options.slideShowThumbnail != null) {
                slideThumbList  = $("#"+options.slideShowThumbnail+" div");
                if(slideThumbList.length > 0){
                    setUpThumbnailOnHover();
                }           
            }               
            
            setUpSlideShow();
        }
        init();
        
        
    }//slideshow class
    
    
})(jQuery);

