/*global jQuery */

(function ($) {

    /* 

    Properties:
    - options
    - container
    - slides
    - pointer
    - total
    - intval

    Methods:
    - playng()
    - start()
    - stop()
    - prepare()
    - startTimer()
    - advance()

    */

    var SlideShow;


    // -------------------------------------------------------------------------
    // Constructor

    SlideShow = function (container, options) {

        var that, slides, i;

        this.options = $.extend({}, SlideShow.defaultOptions, options);
        this.container = container;
        this.intval = null;
        this.stage = this.container.find(this.options.stage);
        slides = this.container.find(this.options.slide);
        this.pointer = 0;
        this.total = slides.length;

        // Store the slides as jQuery wrapped elements.
        this.slides = [];

        for (i = 0; i < this.total; i += 1) {
            this.slides.push($(slides[i]));   
        }

        // Randomize the slides.        
        if (this.options.random) {
            this.slides.sort(SlideShow.compareRandom);    
        }

        // Position and display the slides and stage.
        this.prepare();

        // Start the slideshow.
        if (this.options.autoStart) {

            if (this.options.delay > 0) {
                that = this;
                setTimeout(function () {
                    that.start();
                }, this.options.delay);    
            }

            else {
                this.start();    
            }

        }

    };



    // -------------------------------------------------------------------------
    // Prototype 

    SlideShow.prototype = {


        // Return if the slideshow is active.
        playing: function () {
            return (this.intval !== null);
        },


        // Start the rotation.
        start: function () {
            if (!this.playing()) {
                this.advance();
                this.startTimer();         
            } 
        },


        // Clear the interval to stop the slideshow.        
        stop: function () {
            clearInterval(this.intval);
            this.intval = null;
        },


        // Position and display the slides and stage.
        prepare: function () {

            var i;

            // Show the first slide.        
            this.slides[0].show();

            // Hide all subsequent slides.
            for (i = 1; i < this.total; i += 1) {
                this.slides[i].hide();
            }

            // Bring the stage into view.
            if (this.stage) {
                this.options.showStage(this.stage);
            }

        },


        // Setup advance() on an interval.
        startTimer: function () {

            var that;

            that = this;

            this.intval = setInterval(function () {
                that.advance();
            }, this.options.speed);

        },


        // Display the next slide.
        advance: function () {

            var prevPointer,
            prevSlide,
            nextSlide;

            // Retain the old page index.
            prevPointer = this.pointer;

            // Advance to the pointer to the new page.
            this.pointer += 1;

            if (this.pointer >= this.total) {
                this.pointer = 0;
            }            

            // Reference the pages.
            nextSlide = this.slides[this.pointer];
            prevSlide = this.slides[prevPointer];

            // Show the new slide
            if (nextSlide && !nextSlide.is(":visible")) {
                this.options.show(nextSlide);
            }

            // Hide the old slide
            if (prevSlide && prevSlide.is(":visible")) {
                this.options.hide(prevSlide);
            }

        }

    };



    // -------------------------------------------------------------------------
    // Static Members 

    SlideShow.defaultOptions = {

        // Selector for Slides
        slide: ".slide",

        // Selector for the stage
        stage: ".stage",

        // Display the slides in random order
        random: false,

        // Slide duraction in milliseconds
        speed: 5000,

        // Time in milliseconds before the show starts
        delay: 0,

        // Start the slide show automatically.
        autoStart: true,        

        // Function called to show the stage once the slides are ready
        showStage: function (elem) {
            elem.css({
                left: 0,
                top: 0    
            });   
        },
        
        // Function called to display a slide
        show: function (elem) {
            elem.show();
        },

        // Function called to hide a slide
        hide: function (elem) {
            elem.hide();    
        }


    };

    SlideShow.compareRandom = function (a, b) {
        return (Math.random() >= 0.5) ? 1 : -1;
    };




    // -------------------------------------------------------------------------
    // Extend jQuery 

    if (typeof $.fn.slideshow === "undefined") {

        $.fn.slideshow = function (options) {

            return this.each(function () {

                var ss;
    
                switch (typeof options) {
    
                case "undefined": 
                case "object":
                    ss = new SlideShow($(this), options);
                    $(this).data('SlideShow', ss);
                    break;
                        
                case "string":
    
                    ss = $(this).data("SlideShow");
    
                    if (ss) {
                        
                        switch (options) {
                        
                        case "start":
                            ss.start();
                            break;
                        
                        case "stop":
                            ss.stop();                            
                            break;
                        
                        }
                                    
                    }
    
                    else {
                        throw new Error("Slideshow must be initialized first.");    
                    }
    
                    break;
                    
                }
            
            
            });
            

        };

    }      

}(jQuery));
