$.widget("ui.ajaxPager", {

    _buildLink: function(rel) {
        var $a = $('<a></a>');
        $a.attr('href', '#');
        $a.attr('rel', rel);
        $a.html(this.options[rel]);
        return $a;
    },

    _buildOptions: function() {
        var options = '';
        for (var i = 1; i <= this.options.pageCount; i++) {
            options += '<option value="' + i + '">' + String.format(this.options.optionFormat, i, this.options.pageCount) + '</option>';
        }
        return options;
    },

    _buildSelect: function() {
        var $select = "";
        $select = $('<select></select>');
        $select.append(this._buildOptions());
        $select.val(this.options.pageNum);
        return $select;
    },

    isLastPage: function() {
        return (this.options.pageNum == this.options.pageCount);
    },

    isFirstPage: function() {
        return (this.options.pageNum == 1);
    },

    _showHideLinks: function() {
        if (this.isLastPage() || this.options.pageCount<2) {
            // last page
            this.$next.hide();
        }
        else {
            this.$next.show();
        }
        if (this.isFirstPage() || this.options.pageCount<2) {
            // first page
            this.$prev.hide();
        }
        else {
            this.$prev.show();
        }
        if (this.options.pageCount<2) {
            // first page
            this.$select.hide();
        }
    },

    _goToPage: function() {
        this._showHideLinks();
        var paramNames = $.address.parameterNames();
        var path = $.address.path();
        if (paramNames.length) {
            var queryStr = '?';
            var addPage = true;
            for (var i in paramNames) {
                if (this.options.urlPrefix == paramNames[i]) {
                    addPage = false;
                    queryStr += paramNames[i] + '=' + this.options.pageNum;
                }
                else {
                    queryStr += paramNames[i] + '=' + $.address.parameter(paramNames[i]);
                }
                queryStr += "&";
            }
            if (addPage) {
                queryStr += this.options.urlPrefix + '=' + this.options.pageNum;
            }
            else {
                queryStr = queryStr.substr(0, queryStr.length - 1);
            }
            $.address.value(path + queryStr);
        }
        else {
            $.address.value(path + '?' + this.options.urlPrefix + '=' + this.options.pageNum);
        }
    },

    _changePageNum: function(pageNum) {
        this.options.pageNum = pageNum;
        this._showHideLinks();
        this.$select.val(this.options.pageNum);
    },

    _init: function() {
        var self = this;

        this.element.addClass('ui-pager');

        this.$select = this._buildSelect();
        this.$prev = this._buildLink('prev');
        this.$next = this._buildLink('next');

        this._showHideLinks();

        this.element.append(this.$prev);
        this.element.append(this.$select);
        this.element.append(this.$next);

        this.$select.change(function() {
            self.options.pageNum = self.$select.val();
            self._goToPage();
        });

        this.$prev.click(function() {
            self.options.pageNum--;
            self.$select.val(self.options.pageNum);
            self._goToPage();
            return false;
        });
        this.$next.click(function() {
            self.options.pageNum++;
            self.$select.val(self.options.pageNum);
            self._goToPage();
            return false;
        });

    },

    pageNum: function() {
        return this.options.pageNum;
    },

    update: function(pageCount, pageNum) {
        if (this.options.pageCount != pageCount) {
            this.options.pageCount = pageCount;
            this.$select.html(this._buildOptions());

            this._changePageNum(pageNum);
        }
        else {
            if (pageNum != this.options.pageNum && pageNum <= this.options.pageCount) {
                this._changePageNum(pageNum);
            }
        }
    }

});

$.extend($.ui.ajaxPager, {
    version: "1.0",
    defaults: {
        pageNum: 1,
        pageCount: 1,
        prev: 'prev',
        next: 'next',
        optionFormat: '{0} of {1}',
        urlPrefix: 'page'
    }
});

$.ui.ajaxPager.getter = "isLastPage, isFirstPage, pageNum";
$.ui.ajaxPager.setter = "update";