;(function($, window, document, undefined) {

var Pager = {
    options: {
        items: 'li',    // the selector to the items to paginate -- required
        
        cycle: false,   // whether to cycle back to beginning when
                        // reaching the last element
        
        page: null,     // the current page
        paginateBy: 1,  // how many items to move per page
        perPage: 1,     // how many items are visible at any given time
        
        elementClass: 'pager',
        itemClass: 'page',
        currentClass: 'current',
        
        // callbacks
        init: null,
        
        // events
        change: null,
        next: null,
        previous: null,
        cycled: null
    },
    
    _create: function() {
        this.element.addClass(this.options.elementClass);
    },
    
    _destroy: function() {
        this.element.removeClass(this.options.elementClass);
    },
    
    destroy: function() {
        this._destroy();
        $.Widget.prototype.destroy.call(this);
    },
    
    _init: function() {
        this.items(this.options.items);
        this._trigger('init');
    },
    
    _setOption: function(key, value) {
        switch (key) {
            case 'page':
                this._showPage(value);
                break;
            default:
                break;
        }
        
        return $.Widget.prototype._setOption.apply(this, arguments);
    },
    
    // internal
    
    _showPage: function(index) {
        var self = this,
            opts = this.options,
            curpage = this._page(),
            dir = curpage != null ? curpage - index : 0 - index,
            cycled = opts.cycle && (Math.abs(dir) === this._pageCount() - 1);
        
        if (curpage != null && dir === 0)
            return;
        
        this._page(index);
        
        this._trigger('change', null, {
            page:               index,
            previousPage:       curpage,
            pageCount:          this._pageCount(),
            pageItems:          this._itemsOnPage(index),
            previousPageItems:  $.isNull(curpage) ? $() : this._itemsOnPage(curpage),
            direction:          dir > 0 ? -1 : 1,
            cycled:             cycled
        });
        
        if (cycled)
            this._trigger('cycled', null, [
                dir > 0 ? -1 : 1, // direction
                this._pageCount() // pagecount
            ]);
        else
            this._trigger(dir > 0 ? 'previous' : 'next');
    },
    
    _showNext: function() {
        if (!this._hasNext()) {
            if (this.options.cycle)
                return this._showPage(0);
            return null;
        }
        return this._showPage(this._page() + 1);
    },
    
    _showPrevious: function() {
        if (!this._hasPrevious()) {
            if (this.options.cycle)
                return this._showPage(this._pageCount() - 1);
            return null;
        }
        return this._showPage(this._page() - 1);
    },
    
    _hasNext: function() {
        return this._page() < this._pageCount() - 1;
    },
    
    _hasPrevious: function() {
        return this._page() > 0;
    },
    
    // get/set
    
    _page: function(index) {
        if ($.isNot(index))
            return this.options.page;
        this.options.page = index;
        return null;
    },
    
    _pageCount: function() {
        return Math.ceil((this._items().length - this.options.perPage) / this.options.paginateBy) + 1;
    },
    
    _items: function(value) {
        if ($.isNot(value))
            return this.options.items;
        this.options.items = $(value, this.element[0])
            .addClass(this.itemClass);
        return null;
    },
    
    _itemsOnPage: function(index) {
        var pby = this.options.paginateBy;
        if ($.isNot(index))
            index = this._page();
        return this._items().slice(index * pby, (index + 1) * pby);
    },
    
    // public
    
    items: function(value) {
        if ($.isNot(value))
            return this._items();
        if ($.isNumber(value))
            return this._itemsOnPage(value);
        this._items(value);
        return this;
    },
    
    page: function(index) {
        if ($.isNot(index))
            return this._page();
        this._showPage(parseInt(index, 10));
        return this;
    },
    
    hasNext: function() {
        return this._hasNext();
    },
    
    hasPrevious: function() {
        return this._hasPrevious();
    },
    
    next: function() {
        this._showNext();
        return this;
    },
    
    previous: function() {
        this._showPrevious();
        return this;
    }
};

var Slideshow = {
    options: {
        interval: 6000,
        autostart: true,
        
        // callbacks
        init: null
    },
    
    _create: function() {
        var self = this;
        
        this._tid = null;
        
        this.pager = this.element.data('pager');
        
        this.pager.widget()
            .bind('pagerchange.slideshow', function(e, ui) {
                self.stop();
                self.start();
            });
        
        if (this.options.autostart)
            this.start();
    },
    
    _destroy: function() {
        this.pager.widget().unbind('pagerchange.slideshow');
    },
    
    destroy: function() {
        this._destroy();
        $.Widget.prototype.destroy.call(this);
    },
    
    _init: function() {
        this._trigger('init');
    },
    
    start: function() {
        var self = this;
        clearTimeout(this._tid);
        this._tid = setTimeout(function() {
            self.pager.next();
        }, this.options.interval);
    },
    
    stop: function() {
        clearTimeout(this._tid);
    }
};

var PagerNav = {
    options: {
        node: null,
        nextButton: '.next a',
        previousButton: '.previous a',
        disabledClass: 'disabled'
    },
    
    _create: function() {
        var self = this;
        
        this.pager = this.element.data('pager');
        
        this.pager.widget()
            .bind('pagerchange.pagernav', function(e, ui) {
                self.refresh();
            });
        
        this.p = $(this.options.previousButton, $(this.options.node, this.pager.widget()).get(0))
            .bind('click.pagernav', function(e) {
                e.preventDefault();
                self.pager.previous();
            });
        
        this.n = $(this.options.nextButton, $(this.options.node, this.pager.widget()).get(0))
            .bind('click.pagernav', function(e) {
                e.preventDefault();
                self.pager.next();
            });
    },
    
    _destroy: function() {
        this.pager.widget().unbind('pagerchange.pagernav');
        this.p.unbind('click.pagernav').removeClass(this.options.disabledClass);
        this.n.unbind('click.pagernav').removeClass(this.options.disabledClass);
    },
    
    destroy: function() {
        this._destroy();
        $.Widget.prototype.destroy.call(this);
    },
    
    _init: function() {
        this.refresh();
    },
    
    refresh: function() {
        var pager = this.pager,
            cssclass = this.options.disabledClass;
        
        if (this.pager.options.cycle && (pager.hasPrevious() || pager.hasNext())) 
            return;
        
        if (pager.hasPrevious())
            this.p.parent().removeClass(cssclass);
        else
            this.p.parent().addClass(cssclass);
        
        if (pager.hasNext())
            this.n.parent().removeClass(cssclass);
        else
            this.n.parent().addClass(cssclass);
    }
};

var Paginator = {
    options: {
        node: null,
        buttons: 'a',
        currentClass: 'current'
    },
    
    _create: function() {
        var self = this;
        
        this.pager = this.element.data('pager');
        
        this.pager.widget()
            .bind('pagerchange.paginator', function(e, ui) {
                $(self.options.node)
                    .find(self.options.buttons)
                        .removeClass(self.options.currentClass)
                        .eq(ui.page)
                            .addClass(self.options.currentClass)
                    .end();
            });
        
        $(self.options.node)
            .delegate(this.options.buttons, 'click.paginator', function(e) {
                var button = $(e.target);
                e.preventDefault();
                self.pager.page(parseInt(button.text(), 10) - 1);
            });
    },
    
    _destroy: function() {
        this.pager.widget().unbind('pagerchange.paginator');
        $(self.options.node).undelegate(this.options.buttons, 'click.paginator');
    },
    
    destroy: function() {
        this._destroy();
        $.Widget.prototype.destroy.call(this);
    }
};

$.widget('rad.pager', Pager);
$.widget('rad.slideshow', Slideshow);
$.widget('rad.pagernav', PagerNav);
$.widget('rad.paginator', Paginator);

})(jQuery, this, this.document);

