(function($) {
    var defaults = {
        speed: 4000,
        effect: 'slide',
        selector: '> li',
        height: 'fixed',
        width: 'fixed',
        show: function(){},
        navigation: false
    };

    var helpers = {
        resetTimer : function() {
            var $this = $(this);
            var data = $this.data('ticker');
            clearInterval(data.intervalid);
            var intervalid = setInterval(function(){
                $this.ticker('showNext');
            }, data.speed);
            $this.data('ticker', $.extend(data, {intervalid: intervalid}));
        }
    };

    var methods = {
        init : function(options) {
            return this.each(function() {
                var $this = $(this);
                var data = $this.data('ticker');
                var settings = $.extend({}, defaults, options);

                if (!data) {
                    var $slides = $(settings.selector, $this);
                    $slides.not(':first').hide();

                    if (settings.height !== false) {
                        if (settings.height === 'fixed') {
                            $this.height($this.height());
                        }
                        else if (settings.height === 'max') {
                            var height = 0;
                            $(settings.selector, $this).each(function() {
                                var $item = $(this);
                                var itemHeight = $item.height();
                                if (itemHeight > height) {
                                    height = itemHeight;
                                }
                            });
                            $this.height(height);
                        }
                        else {
                            $this.height(settings.height);
                        }
                    }
                    if (settings.width !== false) {
                        if (settings.width === 'fixed') {
                            $this.width($this.width());
                        }
                        else if (settings.width === 'max') {
                            var width = 0;
                            $(settings.selector, $this).each(function() {
                                var $item = $(this);
                                var itemhHeight = $item.height();
                                if (itemHeight > height) {
                                    height = itemHeight;
                                }
                            });
                            $this.width(width);
                        }
                        else {
                            $this.width(settings.width);
                        }
                    }
                    if (settings.navigation === true) {
                        var $navigation = $('<ul class="ticker-navigation">').insertAfter($this);
                        var i = 0;
                        $slides.each(function() {
                            var index = i;
                            $('<li>' + (index+1) + '</li>')
                                .appendTo($navigation)
                                .bind('click.ticker', function() {
                                    $this.ticker('show', index, false, true);
                                });
                            i++;
                        });
                        $navigation.children(':first').addClass('ticker-navigation-active-item');
                        $this.bind('tickerShow.ticker', function(e, index) {
                            $navigation.children('.ticker-navigation-active-item').removeClass('ticker-navigation-active-item');
                            $navigation.children(':nth-child('+(index+1)+')').addClass('ticker-navigation-active-item');
                        });
                    }
                    if (settings.show) {
                        $this.bind('tickerShow.ticker', settings.show);
                    }

                    $this.data('ticker', {
                        navigation: (settings.navigation === true) ? $navigation : false,
                        effect: settings.effect,
                        speed: settings.speed,
                        slides: $slides,
                        current: 0
                    });

                    $this.ticker('start');
                }
            });
        },

        destroy : function() {
            return this.each(function() {
                var $this = $(this);
                var data = $this.data('ticker');
                $this.ticker('stop');
                $this.unbind('.ticker');
                if (data.navigation) {
                    data.navigation.remove();
                }
                $this.removeData('ticker');
            });
        },

        show : function(index, effect, reset) {
            reset = reset || false;

            return this.each(function () {
                var $this = $(this);
                var data = $this.data('ticker');
                var current = data.current;

                $this.trigger('tickerShow', [index]);

                effect = effect || data.effect;
                if (index !== current) {
                    $this.data('ticker', $.extend(data, {current: index}));

                    // User clicks through faster than animation completes so stop animation on everything except
                    // The currently visible item and hide it
                    data.slides.not($(data.slides[current])).stop(true, true).hide();

                    if (effect === 'slide') {
                        $(data.slides[current]).slideUp();
                        $(data.slides[index]).slideDown();
                    }
                    else if (effect === 'fade') {
                        $(data.slides[current]).fadeOut(function() {
                            $(data.slides[index]).fadeIn();
                        });
                    }
                }
                if (reset === true) {
                    helpers.resetTimer.call($this, data.speed);
                }
            });
        },

        showNext : function(effect) {
            return this.each(function() {
                var $this = $(this);
                var data = $this.data('ticker');
                $this.ticker('show', (data.current+1)%data.slides.length, effect);
            });
        },

        stop : function() {
            return this.each(function() {
                var $this = $(this);
                var data = $this.data('ticker');
                clearInterval(data.intervalid);
                $this.data('ticker', $.extend(data, {intervalid: null}));
            });
        },

        start : function() {
            return this.each(function() {
                var $this = $(this);
                var data = $this.data('ticker');
                var intervalid  = setInterval(function() {
                    $this.ticker('showNext');
                }, data.speed);
                $this.trigger('tickerShow', data.current);
                $this.data('ticker', $.extend(data, {intervalid: intervalid}));
            });
        }
    };

    $.fn.ticker = function(method) {
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        }
        else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        }
        else {
            $.error('Method ' + method + ' does not exist on jQuery.ticker');
        }
    }
})(jQuery);
