/*
Paginator 3000
- idea by ecto (ecto.ru)
- coded by karaboz (karaboz.ru)

How to implement:
<div class="paginator" id="paginator_example"></div>
<script type="text/javascript">
paginator_example = new Paginator('paginator_example', 2048, 10, 1, 'http://www.yourwebsite.com/pages/');
</script>

Be sure that width of your paginator does not change after page is loaded
If it happens you must call Paginator.resizePaginator(paginator_example) function to redraw paginator

*/

/*
Paginator class
paginatorHolderId - id of the html element where paginator will be placed as innerHTML (String): required
pagesTotal - number of pages (Number, required)
pagesSpan - number of pages which are visible at once (Number, required) 
pageCurrent - the number of current page (Number, required)
baseUrl - the url of the website (String)
if baseUrl is 'http://www.yourwebsite.com/pages/' the links on the pages will be:
http://www.yourwebsite.com/pages/1, http://www.yourwebsite.com/pages/2,	etc
*/
var Paginator = function(paginatorHolderId, pagesTotal, pagesSpan, pageCurrent, baseUrl, clickFunction) {
    if (!document.getElementById(paginatorHolderId) || !pagesTotal || !pagesSpan) return false;

    this.inputData = {
        paginatorHolderId: paginatorHolderId,
        pagesTotal: pagesTotal,
        pagesSpan: pagesSpan < pagesTotal ? pagesSpan : pagesTotal,
        pageCurrent: pageCurrent,
        baseUrl: baseUrl ? baseUrl : '/pages/',
        clickFunction: clickFunction  // pavlikov's code
    };

    this.html = {
        holder: null,

        table: null,
        trPages: null,
        trScrollBar: null,
        tdsPages: null,

        scrollBar: null,
        scrollThumb: null,

        pageCurrentMark: null
    };


    this.prepareHtml();

    this.initScrollThumb();
    this.initPageCurrentMark();
    this.initEvents();

    this.scrollToPageCurrent();
}

/*
Set all .html properties (links to dom objects)
*/
Paginator.prototype.prepareHtml = function() {

    this.html.holder = document.getElementById(this.inputData.paginatorHolderId);
    this.html.holder.innerHTML = this.makePagesTableHtml();

    this.html.table = this.html.holder.getElementsByTagName('table')[0];

    var trPages = this.html.table.getElementsByTagName('tr')[0];
    this.html.tdsPages = trPages.getElementsByTagName('td');

    this.html.scrollBar = getElementsByClassName(this.html.table, 'div', 'scroll_bar')[0];
    this.html.scrollThumb = getElementsByClassName(this.html.table, 'div', 'scroll_thumb')[0];
    this.html.pageCurrentMark = getElementsByClassName(this.html.table, 'div', 'current_page_mark')[0];

    // hide scrollThumb if there is no scroll (we see all pages at once)
    if (this.inputData.pagesSpan == this.inputData.pagesTotal) {
        addClass(this.html.holder, 'fullsize');
    }
}

/*
Make html for pages (table) 
*/
Paginator.prototype.makePagesTableHtml = function() {
    var tdWidth = (100 / this.inputData.pagesSpan) + '%';

    var html = '' +
	'<table width="100%">' +
		'<tr>'
    for (var i = 1; i <= this.inputData.pagesSpan; i++) {
        html += '<td width="' + tdWidth + '"></td>';
    }
    html += '' +
		'</tr>' +
		'<tr>' +
			'<td colspan="' + this.inputData.pagesSpan + '">' +
				'<div class="scroll_bar">' +
					'<div class="scroll_trough"></div>' +
					'<div class="scroll_thumb">' +
						'<div class="scroll_knob"></div>' +
					'</div>' +
					'<div class="current_page_mark"></div>' +
				'</div>' +
			'</td>' +
		'</tr>' +
	'</table>';

    return html;
}

/*
Set all needed properties for scrollThumb and it's width
*/
Paginator.prototype.initScrollThumb = function() {
    this.html.scrollThumb.widthMin = '8'; // minimum width of the scrollThumb (px)
    this.html.scrollThumb.widthPercent = this.inputData.pagesSpan / this.inputData.pagesTotal * 100;

    this.html.scrollThumb.xPosPageCurrent = (this.inputData.pageCurrent - Math.round(this.inputData.pagesSpan / 2)) / this.inputData.pagesTotal * this.html.table.offsetWidth;
    this.html.scrollThumb.xPos = this.html.scrollThumb.xPosPageCurrent;

    this.html.scrollThumb.xPosMin = 0;
    this.html.scrollThumb.xPosMax;

    this.html.scrollThumb.widthActual;

    this.setScrollThumbWidth();

}

Paginator.prototype.setScrollThumbWidth = function() {
    // Try to set width in percents
    this.html.scrollThumb.style.width = this.html.scrollThumb.widthPercent + "%";

    // Fix the actual width in px
    this.html.scrollThumb.widthActual = this.html.scrollThumb.offsetWidth;

    // If actual width less then minimum which we set
    if (this.html.scrollThumb.widthActual < this.html.scrollThumb.widthMin) {
        this.html.scrollThumb.style.width = this.html.scrollThumb.widthMin + 'px';
    }

    this.html.scrollThumb.xPosMax = this.html.table.offsetWidth - this.html.scrollThumb.widthActual;
}

Paginator.prototype.moveScrollThumb = function() {
    this.html.scrollThumb.style.left = this.html.scrollThumb.xPos + "px";
}


/*
Set all needed properties for pageCurrentMark, it's width and move it
*/
Paginator.prototype.initPageCurrentMark = function() {
    this.html.pageCurrentMark.widthMin = '3';
    this.html.pageCurrentMark.widthPercent = 100 / this.inputData.pagesTotal;
    this.html.pageCurrentMark.widthActual;

    this.setPageCurrentPointWidth();
    this.movePageCurrentPoint();
}

Paginator.prototype.setPageCurrentPointWidth = function() {
    // Try to set width in percents
    this.html.pageCurrentMark.style.width = this.html.pageCurrentMark.widthPercent + '%';

    // Fix the actual width in px
    this.html.pageCurrentMark.widthActual = this.html.pageCurrentMark.offsetWidth;

    // If actual width less then minimum which we set
    if (this.html.pageCurrentMark.widthActual < this.html.pageCurrentMark.widthMin) {
        this.html.pageCurrentMark.style.width = this.html.pageCurrentMark.widthMin + 'px';
    }
}

Paginator.prototype.movePageCurrentPoint = function() {
    if (this.html.pageCurrentMark.widthActual < this.html.pageCurrentMark.offsetWidth) {
        this.html.pageCurrentMark.style.left = (this.inputData.pageCurrent - 1) / this.inputData.pagesTotal * this.html.table.offsetWidth - this.html.pageCurrentMark.offsetWidth / 2 + "px";
    } else {
        this.html.pageCurrentMark.style.left = (this.inputData.pageCurrent - 1) / this.inputData.pagesTotal * this.html.table.offsetWidth + "px";
    }
}



/*
Drag, click and resize events
*/
Paginator.prototype.initEvents = function() {
    var _this = this;

    this.html.scrollThumb.onmousedown = function(e) {
        if (!e) var e = window.event;
        e.cancelBubble = true;
        if (e.stopPropagation) e.stopPropagation();

        var dx = getMousePosition(e).x - this.xPos;
        document.onmousemove = function(e) {
            if (!e) var e = window.event;
            _this.html.scrollThumb.xPos = getMousePosition(e).x - dx;

            // the first: draw pages, the second: move scrollThumb (it was logically but ie sucks!)
            _this.moveScrollThumb();
            _this.drawPages();


        }
        document.onmouseup = function() {
            document.onmousemove = null;
            _this.enableSelection();
        }
        _this.disableSelection();
    }

    this.html.scrollBar.onmousedown = function(e) {
        if (!e) var e = window.event;
        if (matchClass(_this.paginatorBox, 'fullsize')) return;

        _this.html.scrollThumb.xPos = getMousePosition(e).x - getPageX(_this.html.scrollBar) - _this.html.scrollThumb.offsetWidth / 2;

        _this.moveScrollThumb();
        _this.drawPages();


    }

    // Comment the row beneath if you set paginator width fixed
    addEvent(window, 'resize', function() { Paginator.resizePaginator(_this) });
}

/*
Redraw current span of pages
*/
Paginator.prototype.drawPages = function() {

    //alert(this.html.scrollThumb.xPos);
    //alert(this.html.table.offsetWidth);

    var percentFromLeft = this.html.scrollThumb.xPos / (this.html.table.offsetWidth);

    //alert(percentFromLeft);
    //alert(this.inputData.pagesTotal);

    var cellFirstValue = Math.round(percentFromLeft * this.inputData.pagesTotal);

    var html = "";
    // drawing pages control the position of the scrollThumb on the edges!
    if (cellFirstValue < 1) {
        cellFirstValue = 1;
        this.html.scrollThumb.xPos = 0;
        this.moveScrollThumb();
    } else if (cellFirstValue >= this.inputData.pagesTotal - this.inputData.pagesSpan) {
        cellFirstValue = this.inputData.pagesTotal - this.inputData.pagesSpan + 1;
        this.html.scrollThumb.xPos = this.html.table.offsetWidth - this.html.scrollThumb.offsetWidth;
        this.moveScrollThumb();
    }

    //alert(cellFirstValue);

    for (var i = 0; i < this.html.tdsPages.length; i++) {


        var cellCurrentValue = cellFirstValue + i;



        if (cellCurrentValue == this.inputData.pageCurrent) {
            html = "<span>" + "<strong>" + cellCurrentValue + "</strong>" + "</span>";
        } else {

            // original string html = "<span>" + "<a href='" + this.inputData.baseUrl + cellCurrentValue + "'>" + cellCurrentValue + "</a>" + "</span>";

            // pavlikov's code start  

            if (this.inputData.clickFunction != undefined && this.inputData.clickFunction.length > 0)
                html = "<span>" + "<a  rel='nofollow' href='" + this.inputData.baseUrl + cellCurrentValue + "' onclick=' return " + this.inputData.clickFunction + "(" + cellCurrentValue + ");'>" + cellCurrentValue + "</a>" + "</span>";
            else
                html = "<span>" + "<a  rel='nofollow' href='" + this.inputData.baseUrl + cellCurrentValue + "'>" + cellCurrentValue + "</a>" + "</span>";

            // pavlikov's code end  

        }
        this.html.tdsPages[i].innerHTML = html;
    }
}

/*
Scroll to current page
*/
Paginator.prototype.scrollToPageCurrent = function() {
    this.html.scrollThumb.xPosPageCurrent = (this.inputData.pageCurrent - Math.round(this.inputData.pagesSpan / 2)) / this.inputData.pagesTotal * this.html.table.offsetWidth;
    this.html.scrollThumb.xPos = this.html.scrollThumb.xPosPageCurrent;

    this.moveScrollThumb();
    this.drawPages();

}



Paginator.prototype.disableSelection = function() {
    document.onselectstart = function() {
        return false;
    }
    this.html.scrollThumb.focus();
}

Paginator.prototype.enableSelection = function() {
    document.onselectstart = function() {
        return true;
    }
}

/*
Function is used when paginator was resized (window.onresize fires it automatically)
Use it when you change paginator with DHTML
Do not use it if you set fixed width of paginator
*/
Paginator.resizePaginator = function(paginatorObj) {

    paginatorObj.setPageCurrentPointWidth();
    paginatorObj.movePageCurrentPoint();

    paginatorObj.setScrollThumbWidth();
    paginatorObj.scrollToPageCurrent();
}




/*
Global functions which are used
*/
function getElementsByClassName(objParentNode, strNodeName, strClassName) {
    var nodes = objParentNode.getElementsByTagName(strNodeName);
    if (!strClassName) {
        return nodes;
    }
    var nodesWithClassName = [];
    for (var i = 0; i < nodes.length; i++) {
        if (matchClass(nodes[i], strClassName)) {
            nodesWithClassName[nodesWithClassName.length] = nodes[i];
        }
    }
    return nodesWithClassName;
}


function addClass(objNode, strNewClass) {
    replaceClass(objNode, strNewClass, '');
}

function removeClass(objNode, strCurrClass) {
    replaceClass(objNode, '', strCurrClass);
}

function replaceClass(objNode, strNewClass, strCurrClass) {
    var strOldClass = strNewClass;
    if (strCurrClass && strCurrClass.length) {
        strCurrClass = strCurrClass.replace(/\s+(\S)/g, '|$1');
        if (strOldClass.length) strOldClass += '|';
        strOldClass += strCurrClass;
    }
    objNode.className = objNode.className.replace(new RegExp('(^|\\s+)(' + strOldClass + ')($|\\s+)', 'g'), '$1');
    objNode.className += ((objNode.className.length) ? ' ' : '') + strNewClass;
}

function matchClass(objNode, strCurrClass) {
    return (objNode && objNode.className.length && objNode.className.match(new RegExp('(^|\\s+)(' + strCurrClass + ')($|\\s+)')));
}


function addEvent(objElement, strEventType, ptrEventFunc) {
    if (objElement.addEventListener)
        objElement.addEventListener(strEventType, ptrEventFunc, false);
    else if (objElement.attachEvent)
        objElement.attachEvent('on' + strEventType, ptrEventFunc);
}
function removeEvent(objElement, strEventType, ptrEventFunc) {
    if (objElement.removeEventListener) objElement.removeEventListener(strEventType, ptrEventFunc, false);
    else if (objElement.detachEvent) objElement.detachEvent('on' + strEventType, ptrEventFunc);
}


function getPageY(oElement) {
    var iPosY = oElement.offsetTop;
    while (oElement.offsetParent != null) {
        oElement = oElement.offsetParent;
        iPosY += oElement.offsetTop;
        if (oElement.tagName == 'BODY') break;
    }
    return iPosY;
}

function getPageX(oElement) {
    var iPosX = oElement.offsetLeft;
    while (oElement.offsetParent != null) {
        oElement = oElement.offsetParent;
        iPosX += oElement.offsetLeft;
        if (oElement.tagName == 'BODY') break;
    }
    return iPosX;
}

function getMousePosition(e) {
    if (e.pageX || e.pageY) {
        var posX = e.pageX;
        var posY = e.pageY;
    } else if (e.clientX || e.clientY) {
        var posX = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
        var posY = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
    }
    return { x: posX, y: posY }
}


