// quotator version 1.0.1
(function($) {
    $.fn.quotator = function(options) {
        var options = $.extend(true, {}, $.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
        delay: 0, 										// ms of delay before animation
        timer: 5,                       					// seconds
        contentSelector: 'div.content', 							// css selector to find quotes within quotator
        target: {
            selector: false,           							// selector must match number of content selectors    
            event: 'click'              						// space delimited events to invoke content swap
        },
        fx: 'fade', 									//fade|slide
        easing: 'swing',
        hasNext: false,
        hasBack: false,
        activeIndex: 0,
        activeClass: 'active',
        asynchronousEffect: false,
        position: 'absolute',
        complete: function() { } 							//function to performe logic when animation finishes
    };


    // instantiator
    var quotator = function(element, options) {
        var self = this;
        element.css({
            'position': 'relative'
        });

        var content_els_css = {
            top: {
                'z-index': '200',
                'opacity': '1'
            },
            mid: {
                'z-index': '50',
                'opacity': '0'
            },
            bottom: {
                'z-index': '0',
                'opacity': '0'
            }
        };

        var content_els = element.find(options.contentSelector).each(function(index) {
            var t = $(this);
            t.attr('index', index);
            if (index == options.activeIndex) {
                t.addClass(options.activeClass);
                t.css(content_els_css.top)
            }
            else {
                t.css(content_els_css.bottom).hide();
            }
        }).css({
            'position': options.position,
            'top': '0px',
            'left': '0px'
        });

        if (jQuery.browser.msie && content_els.get(options.activeIndex))
            content_els.get(options.activeIndex).style.removeAttribute('filter');

        self.logic = {
            animationComplete: function(active, lastActive) {
                if (jQuery.browser.msie) {
                    active.get(0).style.removeAttribute('filter');
                    lastActive.get(0).style.removeAttribute('filter');
                }
                self.logic.isAnimating = false;
                if (options.complete && typeof options.complete == 'function')
                    options.complete.call(active, active, lastActive);
            },
            setActiveTargets: function(active, lastActive) {
                var toTarget = target_els.get(active.attr('index'))
                var fromTarget = target_els.get(lastActive.attr('index'))
                if (toTarget && fromTarget) {
                    $([toTarget, fromTarget]).toggleClass('active');
                }
            },
            isAnimating: false,
            animationOver: function() {
                self.logic.isAnimating = false;
            },
            getQuote: function(direction, goToIndex) {
                if (goToIndex) {
                    self.timer.reset();
                    var current = content_els.filter('.' + options.activeClass);
                    if (direction < 0 || direction > content_els.length - 1 || direction == current.attr('index')) {
                        //throw new Error('Invalid move operation.')
                        return false;
                    }

                    var lastActiveQuote = content_els.filter('.' + options.activeClass);
                    lastActiveQuote.removeClass(options.activeClass);
                    var activeQuote = $(content_els[direction]);
                    activeQuote.addClass(options.activeClass);
                    return { active: activeQuote, lastActive: lastActiveQuote };
                }

                if (direction == -1) {
                    var lastActiveQuote = content_els.filter('.' + options.activeClass);
                    lastActiveQuote.removeClass(options.activeClass);
                    var activeQuote = lastActiveQuote.prev(options.contentSelector);
                    if (!activeQuote[0])
                        activeQuote = content_els.filter(':last');
                    activeQuote.addClass(options.activeClass);
                    return { active: activeQuote, lastActive: lastActiveQuote };
                }
                else if (direction == 1) {
                    var lastActiveQuote = content_els.filter('.' + options.activeClass);
                    lastActiveQuote.removeClass(options.activeClass);
                    var activeQuote = lastActiveQuote.next(options.contentSelector);
                    if (!activeQuote[0])
                        activeQuote = content_els.filter(':first');
                    activeQuote.addClass(options.activeClass);
                    return { active: activeQuote, lastActive: lastActiveQuote };
                }
            }
        };

        // create move object 
        // return move object
        self.fx = {
            fade: {
                next: function() {
                    this.move(1);
                },
                back: function() {
                    this.move(-1);
                },
                move: function(dir, goToIndex) {
                    // stop if animating
                    if (!options.asynchronousEffect && self.logic.isAnimating) return false;
                    // get quote to and from
                    if (options.delay > 0) {
                        var timeout = setTimeout(function() {
                            var item;
                            for (var i = 0; item = self.queue[i]; i++) {
                                if (item == timeout) {
                                    window.clearTimeout(timeout);
                                    self.queue = [];
                                    return self.animate._move(dir, goToIndex);
                                }
                            }

                        }, options.delay);
                        self.queue.push(timeout);
                        return;
                    };
                    this._move(dir, goToIndex);
                },
                _move: function(dir, goToIndex) {
                    var lq = self.logic.getQuote(dir, goToIndex);
                    if (!lq) return false;
                    //valid quote, begin animating
                    self.logic.isAnimating = true;
                    lq.active.css(content_els_css.mid).show();

                    if (options.duration <= 0) { // no duration then dont animate
                        lq.lastActive.css(content_els_css.bottom).hide();
                        lq.active.css(content_els_css.top);
                        self.logic.animationComplete(lq.active, lq.lastActive);
                    }
                    else {
                        lq.active.animate({ opacity: 1 }, {
                            duration: options.duration,
                            easing: options.easing
                        });

                        lq.lastActive.animate({ opacity: 0 }, {
                            duration: options.duration,
                            easing: options.easing,
                            complete: function() {
                                lq.lastActive.css(content_els_css.bottom).hide();
                                lq.active.css(content_els_css.top);
                                self.logic.animationComplete(lq.active, lq.lastActive);
                            }
                        });
                    }
                    self.logic.setActiveTargets(lq.active, lq.lastActive);
                }
            },
            slide: {
                next: function() {
                    this.move(1);
                },
                back: function() {
                    this.move(-1);
                },
                move: function(dir, goToIndex) {
                    // stop if animating
                    if (!options.asynchronousEffect && self.logic.isAnimating) return false;
                    // get quote to and from
                    if (options.delay > 0) {
                        var timeout = setTimeout(function() {
                            var item;
                            for (var i = 0; item = self.queue[i]; i++) {
                                if (item == timeout) {
                                    window.clearTimeout(timeout);
                                    self.queue = [];
                                    return self.animate._move(dir, goToIndex);
                                }
                            }

                        }, options.delay);
                        self.queue.push(timeout);
                        return;
                    };
                    this._move(dir, goToIndex);
                },
                _move: function(dir, goToIndex) {
                    var lq = self.logic.getQuote(dir, goToIndex);
                    if (!lq) return false;
                    //valid quote, begin animating
                    self.logic.isAnimating = true;
                    if (goToIndex) {
                        var lastIndex = lq.lastActive.attr('index');
                        var index = lq.active.attr('index');
                        dir = index > lastIndex ? 1 : -1;
                    }
                    if (options.duration <= 0) { // no duration then dont animate
                        lq.lastActive.css(content_els_css.bottom).hide();
                        lq.active.css(content_els_css.top).show();
                        self.logic.animationComplete(lq.active, lq.lastActive);
                    }
                    else {
                        if (dir < 0) {
                            lq.active.css(content_els_css.top).show('slide', { direction: 'left' }, options.duration);
                            lq.lastActive.css(content_els_css.top).hide('slide', { direction: 'right' }, options.duration);
                        }
                        else {
                            lq.active.css(content_els_css.top).show('slide', { direction: 'right' }, options.duration);
                            lq.lastActive.css(content_els_css.top).hide('slide', { direction: 'left' }, options.duration);
                        }
                        setTimeout(function() {
                            self.logic.animationComplete(lq.active, lq.lastActive)
                        }, options.duration);
                    }
                    self.logic.setActiveTargets(lq.active, lq.lastActive);
                }
            }
        };

        //self.animate = self.animateFade;
        // populete animate object from options, slide, fade
        self.animate = self.fx[options.fx];

        self.queue = [

		];

        self.timer = {
            self: null,
            start: function() {
                this.stop();
                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();
            }
        };

        var target_els = options.target.selector ? element.find(options.target.selector).each(function(index) {
            var t = $(this);
            t.attr('index', index);
            // stop timer if hover event
            t.bind(options.target.event, function() {
                self.queue = [];
                self.animate.move(index, true);
                self.timer.stop();
                return false;
            });
            // hovers can start timer after hover off
            if (options.target.event.indexOf('mouseover') > -1) {
                t.bind('mouseout', function() {
                    self.timer.start();

                });
            }
            if (index == options.activeIndex) {
                t.addClass(options.activeClass);
            }
        }) : $([]);

        self.targets = target_els;

        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);
