// pattern taken from http://forum.jquery.com/topic/plugin-multiple-instances-with-persistent-var-values

(function($) {
    // define the carousel object
    var carousel = function(elem, opts) {
        // add additional dom elements
        $(elem).wrap('<div class="carousel-wrapper"></div>');
        $(elem).parents('.carousel-wrapper').append('<div class="carousel-controller"></div>');
        $(elem).parents('.carousel-wrapper').append('<div class="carousel-captions"></div>');
        $(elem).parents('.carousel-wrapper').find('.carousel-captions').hide();
        
        var options = opts;
        var carousel = $(elem);
        var wrapper = carousel.parents('.carousel-wrapper');
        var controller = wrapper.find('.carousel-controller');
        var captions = wrapper.find('.carousel-captions');
        var items = carousel.find('li');
        var current = null;
        var prev = null;
        var next = null;
        var timer = null;
        
        init();
        
        /**
         * Initialize the carousel and add necessary classes, ids, etc
         */
        function init() {
            items.each(function(index) {
                i = index + 1;
                $(this).attr('id', 'item-' + i);
                if($(this).is(':nth-child(' + options.offset + ')')) {
                    current = $(this);
                } else {
                    $(this).hide();
                }
            });
                
            setDimensions();
            if(options.show_controls || options.show_pager || options.show_pause) setControls();    
            setState();
            if(options.autoplay) start();
        }
        
        /**
         * Set the dimensions of the carousel wrapper element. If no height and width are set in the options,
         * the height and width of the first item in the carousel will be used
         */
        function setDimensions () {
            h = (options.height == null) ? current.outerHeight() : options.height;
            w = (options.width == null) ? current.outerWidth() : options.width;
            wrapper.css({ height: h + 'px', width: w + 'px' });
        }
        
        /**
         * Build the various controls for the carousel.  All controls can be disabled by their respective variables in the options object
         * @var options.show_pause Play / Pause button for starting / stopping the slideshow
         * @var options.show_controls Next / Previous buttons
         * @var options.show_pager Individual links for each item
         */ 
        function setControls() {
            if(options.show_pause) {
                if(options.autoplay) controller.append('<a href="" class="carousel-pause-button" id="' + 'link-pause" rel="pause"><span class="carousel-button-text">Pause</span></a>')
                else controller.append('<a href="" class="carousel-play-button" id="' + 'link-play" rel="play"><span class="carousel-button-text">Play</span></a>')
            }
            if(options.show_controls) {
                controller.append('<a href="" class="carousel-prev-button" id="' + 'link-prev" rel="prev"><span class="carousel-button-text">' + options.prev_text + '</span></a>');
            }
            if(options.show_pager) {
                items.each(function(index) {
                    i = index + 1;
                    controller.append('<a href="" class="carousel-item-button" id="' + 'link-' + i + '" rel="' + i + '"><span class="carousel-button-text">' + i + '</span></a>');
                });
            }
            if(options.show_controls) {
                controller.append('<a href="" class="carousel-next-button" id="' + 'link-next" rel="next"><span class="carousel-button-text">' + options.next_text + '</span></a>');
            }              
            // bind the controller behaviors
            controller.find('a').bind('click', function(e) {
                e.preventDefault();
                var action = $(this).attr('rel');
                if(action != 'play') stop();
                change(action);
            });
        }
        
        /**
         * Sets the current state of the carousel including which items will be assigned to the 'Previous' and 'Next' buttons
         * and which pager item is the currently active item
         */
        function setState() {
            switch(true) {
                case current.is('li:first-child'):
                    next = current.next();
                    prev = carousel.find('li:last-child');
                    break;
                case current.is('li:last-child'):
                    next = carousel.find('li:first-child');
                    prev = current.prev();
                    break;            
                default:
                    next = current.next();
                    prev = current.prev();
                    break;
            }
            
            if(current.find(':first-child').is('img')) {
                var alt = current.find(':first-child').attr('alt');
                if(alt) {
                    captions.html(alt);
                    if(captions.css('display') == 'none') {
                        captions.slideDown();
                    }
                } else {
                    captions.slideUp();
                }
            }
            
            // set the active class for the nav item
            if(options.show_pager) {
                controller.find('a.current').removeClass('current');
                var id = current.attr('id').replace('item-', '');
                controller.find('#' + 'link-' + id).addClass('current');
            }
        }
        
        /**
         * Start the slideshow
         */
        function start() {
            timer = setInterval(function() {
                change('next');
            }, options.delay);
            controller.find('.carousel-play-button').removeClass('carousel-play-button').addClass('carousel-pause-button').attr('rel', 'pause').find('span.carousel-button-text').html('Pause');
        }
        
        /**
         * Stop the slideshow
         */
        function stop() {
            clearInterval(timer);
            controller.find('.carousel-pause-button').removeClass('carousel-pause-button').addClass('carousel-play-button').attr('rel', 'play').find('span.carousel-button-text').html('Play');
        }
        
        /**
         * Change the slide
         * @param delta (mixed) Argument for how to change the slide
         */
        function change(delta) {
            switch(delta) {
                case 'prev':
                    current.fadeOut(options.transition);
                    prev.fadeIn(options.transition);
                    current = prev;
                    setState();
                    break;
                case 'next':
                    current.fadeOut(options.transition);
                    next.fadeIn(options.transition);
                    current = next;
                    setState();
                    break;
                case 'play':
                    start();
                    break;
                case 'pause':
                    stop();
                    break;
                default:
                    if(delta != current.attr('id').replace('item-', '')) {
                        next = carousel.find('li#' + 'item-' + delta);
                        current.fadeOut(options.transition);
                        next.fadeIn(options.transition);
                        current = next;
                        setState();
                    }
                    break;
            }
        }
    };
    // end object definition



    /**
     * create the plugin
     */
    $.fn.carousel = function(opts) {
        // overwrite defaults with passed options
        var options = $.extend({}, $.fn.carousel.defaults, opts);
        // return for chaining
        return this.each(function() {
            new carousel($(this), options);
        });
    };
    
    /**
     * default options
     */
    $.fn.carousel.defaults = {
        autoplay: false,
        delay: 5000,
        transition: 800,
        // height: null,
        // width: null,
        show_controls: true,
        show_pause: true,
        show_pager: true,
        next_text: '&raquo;',
        prev_text: '&laquo;',
        offset: 1
    };
    
})(jQuery);
