var Paginator = function(paginatorHolderId, pagesTotal, pagesSpan, pageCurrent, pattern ){
	if(!document.getElementById(paginatorHolderId) || !pagesTotal || !pagesSpan) return false;
	this.inputData = {
		paginatorHolderId: paginatorHolderId,
		pagesTotal: pagesTotal,
		pagesSpan: pagesSpan < pagesTotal ? pagesSpan : pagesTotal,
		enteredPagesSpan: pagesSpan,
		pageCurrent: pageCurrent,
		Pattern: pattern
	};

	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();

	this.html.scrollThumb.style.visibility = 'hidden';
	this.html.scrollBar.style.visibility = 'hidden';
} 

/*
	Set all .html properties (links to dom objects)
*/
Paginator.prototype.prepareHtml = function() {
    this.html.holder = document.getElementById(this.inputData.paginatorHolderId);
    $(this.html.holder).mouseover(function() {

        $(".scroll_bar").css('visibility', 'visible');

        $(".scroll_thumb").css('visibility', 'visible');
    });
    $(this.html.holder).mouseout(function() {
        $(".scroll_bar").css('visibility', 'hidden');
        $(".scroll_thumb").css('visibility', 'hidden');
    });
    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');
        $(".scroll_bar").css("display", "none");
    }
}

/*
	Make html for pages (table) 
*/
Paginator.prototype.makePagesTableHtml = function() {
    var LessThenPageSpan = this.inputData.pagesTotal < this.inputData.enteredPagesSpan;
    var tdWidth = LessThenPageSpan
       ? (100 / this.inputData.enteredPagesSpan) + '%'
        : (100 / this.inputData.pagesSpan) + '%';

    var html = '<table width="100%"><tr>' + (LessThenPageSpan ? '<th></th>' : '');
    for (var i = 1; i <= this.inputData.pagesSpan; i++) {
        html += '<td width="' + tdWidth + '"></td>';
    }
    
    html += (LessThenPageSpan ? '<th></th>' : '') +
		'</tr>' +
		'<tr>' +
			'<td colspan="' + (this.inputData.pagesSpan + (LessThenPageSpan ? 2 : 0)) + '">' +
				'<div class="scroll_bar">' +
					'<div class="scroll_trough"></div>' +
					'<div class="scroll_thumb"><i></i><b></b><u></u>' +
						'<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.inputData.pagesTotal == this.inputData.pageCurrent) {
        this.html.pageCurrentMark.style.right = '0px';
        this.html.pageCurrentMark.style.left = 'auto';

    } else {
        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() {
    var percentFromLeft = this.html.scrollThumb.xPos / (this.html.table.offsetWidth);
    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();
    }

    var startIndex = 1;
    this.html.tdsPages[0].innerHTML = this.inputData.pageCurrent == 1 ? "<span >" + "<strong>" + 1 + "</strong>" + "</span>" : "<span style='text-align:center'>" + "<a href='" + this.inputData.Pattern.replace("{0}", 1) + "'>" + 1 + "</a>" + "</span>";
    if (cellFirstValue > 1) {
        this.html.tdsPages[1].innerHTML = "<span><b>...</b></span>";
        startIndex = 2;
    }


    for (var i = startIndex; i < this.html.tdsPages.length - 1; i++) {
        var cellCurrentValue = cellFirstValue + i;
        if (cellCurrentValue == this.inputData.pageCurrent) {
            html = "<span>" + "<strong>" + cellCurrentValue + "</strong>" + "</span>";
        } else {
            html = "<span>" + "<a href='" + this.inputData.Pattern.replace("{0}", cellCurrentValue) + "'>" + cellCurrentValue + "</a>" + "</span>";
            //html = "<span>" + "<a href='" + this.inputData.baseUrl + cellCurrentValue + this.inputData.Sufix + "'>" + cellCurrentValue + "</a>" + "</span>";
        }
        this.html.tdsPages[i].innerHTML = html;
    }

    if ((this.inputData.pagesTotal - cellFirstValue) >= this.inputData.pagesSpan) {
        this.html.tdsPages[this.html.tdsPages.length - 2].innerHTML = "<span><b>...</b></span>";
    }

    this.html.tdsPages[this.html.tdsPages.length - 1].innerHTML = this.inputData.pageCurrent == this.inputData.pagesTotal ? "<span>" + "<strong>" + this.inputData.pagesTotal + "</strong>" + "</span>" : "<span>" + "<a href='" + this.inputData.Pattern.replace("{0}", this.inputData.pagesTotal) + "'>" + this.inputData.pagesTotal + "</a>" + "</span>";
}

/*
	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}	
}