(function($) {
    $.fn.quotator = function(options) {
        var options = $.extend({}, $.fn.quotator.defaults, options);
        // create data object to access quotator
        $(this).data('items', []);

        return this.each(function() {
            var self = $(this);
            self.data('items').push(new quotator(self, options));
        });
    };

    $.fn.quotator.defaults = {
        duration: 800,  //ms of animation
        timer: 5,       //seconds
        quoteSelector: 'div.quote',    //css selector to find quotes within quotator
        easing: 'swing',
        hasNext: false,
        hasBack: false,
        activeIndex: 0,
        activeClass: 'quote_active',
        complete: function() { } //function to performe logic when animation finishes
    };


    // instantiator
    var quotator = function(element, options) {
        var self = this;
        element.css({
            'position': 'relative'
        });

        var quote_els_css = {
            top: {
                'z-index': '100',
                'opacity': '1'
            },
            mid: {
                'z-index': '50',
                'opacity': '0'
            },
            bottom: {
                'z-index': '0',
                'opacity': '0'
            }
        };

        var quote_els = element.find(options.quoteSelector).each(function(index) {
            var t = $(this);
            t.attr('index', index);
            if (index == options.activeIndex) {
                t.addClass(options.activeClass);
                t.css(quote_els_css.top)
            }
            else {
                t.css(quote_els_css.bottom)
            }
        }).css({
            'position': 'absolute',
            'top': '0',
            'left': '0'
        });

        self.logic = {
            animationComplete: function(active, lastActive) {
                self.logic.isAnimating = false;
                if (options.complete && typeof options.complete == 'function')
                    options.complete.call(null, active, lastActive);
            },
            isAnimating: false,
            animationOver: function() {
                self.logic.isAnimating = false;
            },
            getQuote: function(direction, goToIndex) {
                if (goToIndex) {
                    //debugger;
                    self.timer.reset();
                    var current = quote_els.filter('.' + options.activeClass);
                    if (direction < 0 || direction > quote_els.length - 1 || direction == current.attr('index')) {
                        //throw new Error('Invalid move operation.')
                        return false;
                    }

                    var lastActiveQuote = quote_els.filter('.' + options.activeClass);
                    lastActiveQuote.removeClass(options.activeClass);
                    var activeQuote = $(quote_els[direction]);
                    activeQuote.addClass(options.activeClass);
                    return { active: activeQuote, lastActive: lastActiveQuote };
                }

                if (direction == -1) {
                    var lastActiveQuote = quote_els.filter('.' + options.activeClass);
                    lastActiveQuote.removeClass(options.activeClass);
                    var activeQuote = lastActiveQuote.prev(options.quoteSelector);
                    if (!activeQuote[0])
                        activeQuote = quote_els.filter(':last');
                    activeQuote.addClass(options.activeClass);
                    return { active: activeQuote, lastActive: lastActiveQuote };
                }
                else if (direction == 1) {
                    var lastActiveQuote = quote_els.filter('.' + options.activeClass);
                    lastActiveQuote.removeClass(options.activeClass);
                    var activeQuote = lastActiveQuote.next(options.quoteSelector);
                    if (!activeQuote[0])
                        activeQuote = quote_els.filter(':first');
                    activeQuote.addClass(options.activeClass);
                    return { active: activeQuote, lastActive: lastActiveQuote };
                }
            }
        };

        // create move object 
        // return move object
        self.animate = {
            next: function() {
                this.move(1);
            },
            back: function() {
                this.move(-1);
            },
            move: function(dir, goToIndex) {
                // stop if animating
                if (self.logic.isAnimating) return false;
                // get quote to and from
                var lq = self.logic.getQuote(dir, goToIndex);
                if (!lq) return false;
                //valid quote, begin animating
                self.logic.isAnimating = true;
                lq.active.css(quote_els_css.mid);
                lq.active.animate(quote_els_css.top, {
                    duration: options.duration,
                    easing: options.easing
                });

                lq.lastActive.animate(quote_els_css.bottom, {
                    duration: options.duration,
                    easing: options.easing,
                    complete: self.logic.animationComplete.apply(null, new Array(lq.active, lq.lastActive))
                });
            }
        };
        self.timer = {
            self: null,
            start: function() {
                if (options.timer && options.timer > 0)
                    this.self = window.setInterval(this.tick, this.interval);
            },
            stop: function() {
                if (options.timer && options.timer > 0)
                    window.clearInterval(this.self);
            },
            interval: options.timer * 1000,
            tick: function() {
                self.animate.next();
            },
            reset: function() {
                this.stop();
                this.start();
            }
        };

        if (options.hasBack) {
            var back = $('<a href="javascript:;" class="arrow">back</a>').click(function() { self.animate.back(); self.timer.stop(); });
            element.after(back);
        }
        if (options.hasNext) {
            var next = $('<a href="javascript:;" class="arrow">next</a>').click(function() { self.animate.next(); self.timer.stop(); });
            element.after(next);
        }

        if (options.timer) self.timer.start();
        
        return self;
    };
})(jQuery);