/**
 * PaginationHelper
 * @author Jae Cho
 * This is code that abstracts out pagination control for a module.
 * This class requires a containing div to be defined in HTML. update method
 * then will draw all the necessary component within the div.
 *                                                           
 * @param titleSelector ID of title to display "(x of n)" text
 * @param pgCtrlNodeId ID of div containing page control. This needs to be specified because there
 * may be multiple pagination control within a page.
 * @param pagingModule reference to a parent module that uses this.
 * @param pageSize size of a page
 *
 * @dependencies Module
 *
 */
function PaginationHelper(titleSelector, topCtrl, bottomCtrl, pagingModule, pageSize) {

    this._titleNode = $(titleSelector);

    this._topCtrl = $(topCtrl);

    this._bottomCtrl = $(bottomCtrl);

    this._pageSize = pageSize;

    this._total = 0;

    this._curIdx = 0;

    /** parent module that contains the pagination control */
    this._module = pagingModule;

    this.getPageSize = function() {
        return this._pageSize;
    };

    this.setPageSize = function(pageSize) {
        this._pageSize = pageSize;
    };

    /** append a page control link */
    this._appendPageLink = function(pageStr, pageInx) {
        this._topCtrl.append("<a>" + pageStr + "</a>");
        this._bottomCtrl.append("<a>" + pageStr + "</a>");
        var func = bindContext(this._module, this._module.handlePageChange, [ pageInx ] );
        this._topCtrl.children("a:last").click(func);
        this._bottomCtrl.children("a:last").click(func);
    };

    /**
     * return array of page indices to display
     * @param curPage
     * @param pageTotal
     */                                                 
    this._getDisplayedPages = function(curPage, pageTotal)
    {
        var chunkStart = Math.min(curPage - 1, pageTotal - 4);
        chunkStart = Math.max(chunkStart, 0);

        var chunkEnd = Math.min(chunkStart + 3, pageTotal - 1);

        var ret = new Array();
        if (chunkStart == 0) chunkStart ++;
        if (chunkEnd == pageTotal - 1) chunkEnd --;

        if (pageTotal > 1) ret.push(0);
        for (var i = chunkStart; i <= chunkEnd; i++) {
            ret.push(i);
        }
        if (pageTotal > 1) ret.push(pageTotal - 1);
        return ret;
    };

    /** update both pagination control and title */
    this.update = function(curIdx, total)
    {
        this.updateTitle(curIdx, total);

        if (total > this._pageSize) {
            this.updateControl(curIdx, total);
            this._topCtrl.show();
            this._bottomCtrl.show();
        } else {
            this._topCtrl.hide();
            this._bottomCtrl.hide();
        }
    };

    /**
     * update title (start - end of total)
     * @param curIdx
     * @param total
     */
    this.updateTitle = function(curIdx, total)
    {
        this._titleNode.empty();

        var title = null;
        if (total <= this._pageSize) {
            title = "" + total;
        } else {
            var end = Math.min(curIdx + this._pageSize - 1, total - 1);
            title = (curIdx + 1) + "-" + (end + 1) + " of " + total;
        }
        
        this._titleNode.html("(" + title + ")");
    };


    /**
     * update pagination control
     * @param curIdx
     * @param total
     */
    this.updateControl = function(curIdx, total)
    {
        this._topCtrl.empty();
        this._bottomCtrl.empty();

        this._curIdx = curIdx;
        this._total = total;
        var curPage = Math.floor(curIdx / this._pageSize);
        var pageTotal = Math.ceil(total / this._pageSize);

        if (this._total <= this._pageSize) return;

        /** previous page control */
        if (curPage > 0) {
            this._appendPageLink('<a class="searchPgPrev">Previous</a>', curPage - 1);
        }

        var pageArray = this._getDisplayedPages(curPage, pageTotal);
        this._topCtrl.append("Page:");
        this._bottomCtrl.append("Page: ");
        var prevPage = -1;
        for (var i = 0; i < pageArray.length; i++) {
            var pageNum = pageArray[i];

            if (prevPage + 1 < pageNum) {
                this._topCtrl.append("...");
                this._bottomCtrl.append("...");
			} else {
                this._topCtrl.append("&nbsp;");
                this._bottomCtrl.append("&nbsp;");
            }
            
            if (pageNum == curPage) {
                this._topCtrl.append("" + (pageNum + 1));
                this._bottomCtrl.append("" + (pageNum + 1));
            } else {
                this._appendPageLink("" + (pageNum + 1), pageNum);
            }

			if (pageNum == curPage && curPage == pageTotal - 1){
                this._topCtrl.append("&nbsp;");
                this._bottomCtrl.append("&nbsp;");
			}

            prevPage = pageNum;
        }

        /** next page control */
        if (curPage < pageTotal - 1) {
            this._topCtrl.append("&nbsp;");
            this._bottomCtrl.append("&nbsp;");
            this._appendPageLink("<a class=\"searchPgNext\">Next</a>", curPage + 1);
        }
    };
}
