/*------------------------------------------------------------------------
	- HTML Table Filter Generator 
	- Paging feature v1.0
	- By Max Guglielmi (tablefilter.free.fr)
	- Licensed under the MIT License
-------------------------------------------------------------------------*/

TF.prototype.SetPaging = function()
/*====================================================
	- Generates paging elements:
		- pages drop-down list
		- previous, next, first, last buttons
=====================================================*/
{
	if(!this.hasGrid && !this.isFirstLoad) return;
	if(!this.paging || (!this.isPagingRemoved && !this.isFirstLoad)) return;
	var start_row = this.refRow;
	var nrows = this.nbRows;
	this.nbPages = Math.ceil( (nrows-start_row)/this.pagingLength );//calculates page nb

	//Paging elements events
	if(!this.Evt._Paging.next)
	{
		var o = this;		
		this.Evt._Paging = {// paging buttons events
			slcIndex: function(){ 
				return (o.pageSelectorType==o.fltTypeSlc) 
					? o.pagingSlc.options.selectedIndex 
					: parseInt(o.pagingSlc.value)-1;
			},
			nbOpts: function(){ 
				return (o.pageSelectorType==o.fltTypeSlc) 
				? parseInt(o.pagingSlc.options.length)-1 
				: (o.nbPages-1);
			},
			next: function(){
				if(o.Evt._Paging.nextEvt) o.Evt._Paging.nextEvt();
				var nextIndex = (o.Evt._Paging.slcIndex()<o.Evt._Paging.nbOpts()) 
					? o.Evt._Paging.slcIndex()+1 : 0;
				o.ChangePage(nextIndex);
			},			
			prev: function(){
				if(o.Evt._Paging.prevEvt) o.Evt._Paging.prevEvt();
				var prevIndex = o.Evt._Paging.slcIndex()>0 
					? o.Evt._Paging.slcIndex()-1 : o.Evt._Paging.nbOpts();
				o.ChangePage(prevIndex);
			},			
			last: function(){
				if(o.Evt._Paging.lastEvt) o.Evt._Paging.lastEvt();
				o.ChangePage(o.Evt._Paging.nbOpts());
			},			
			first: function(){
				if(o.Evt._Paging.firstEvt)  o.Evt._Paging.firstEvt();
				o.ChangePage(0);
			},			
			_detectKey: function(e)
			{
				var evt=(e)?e:(window.event)?window.event:null;
				if(evt)
				{
					var key=(evt.charCode)?evt.charCode:
						((evt.keyCode)?evt.keyCode:((evt.which)?evt.which:0));
					if(key=='13'){ 
						if(o.sorted){ o.Filter(); o.ChangePage(o.Evt._Paging.slcIndex()); }
						else o.ChangePage();								
						this.blur(); 
					}
				}//if evt
			},
			nextEvt: null,
			prevEvt: null,
			lastEvt: null,
			firstEvt: null
		}
	}
	
	if(!this.Evt._OnSlcPagesChange)
	{
		this.Evt._OnSlcPagesChange = function()
		/*====================================================
			- onchange event for paging select
		=====================================================*/
		{
			if(o.Evt._Paging._OnSlcPagesChangeEvt)
				o.Evt._Paging._OnSlcPagesChangeEvt();
			o.ChangePage();
			this.blur();
			//ie only: blur is not enough...
			if(this.parentNode && tf_isIE)
				this.parentNode.focus();
		}
	}

	// Paging drop-down list selector
	if(this.pageSelectorType == this.fltTypeSlc)
	{
		var slcPages = tf_CreateElm( this.fltTypeSlc, ['id',this.prfxSlcPages+this.id] );
		slcPages.className = this.pgSlcCssClass;
		slcPages.onchange = this.Evt._OnSlcPagesChange;
	}
	// Paging input selector
	if(this.pageSelectorType == this.fltTypeInp)
	{
		var slcPages = tf_CreateElm( 
			this.fltTypeInp, 
			['id',this.prfxSlcPages+this.id],
			['value',this.currentPageNb]
		);
		slcPages.className = this.pgInpCssClass;
		slcPages.onkeypress = this.Evt._Paging._detectKey;
	}
	
	var btnNextSpan, btnPrevSpan, btnLastSpan, btnFirstSpan;// btns containers
	btnNextSpan = tf_CreateElm('span',['id',this.prfxBtnNextSpan+this.id]);
	btnPrevSpan = tf_CreateElm('span',['id',this.prfxBtnPrevSpan+this.id]);
	btnLastSpan = tf_CreateElm('span',['id',this.prfxBtnLastSpan+this.id]);
	btnFirstSpan = tf_CreateElm('span',['id',this.prfxBtnFirstSpan+this.id]);
	
	if(this.hasPagingBtns)
	{
		if(this.btnNextPageHtml==null)
		{// Next button
			var btn_next = tf_CreateElm( this.fltTypeInp,['id',this.prfxBtnNext+this.id],
				['type','button'],['value',this.btnNextPageText],['title','Next'] );
			btn_next.className = this.btnPageCssClass;
			btn_next.onclick = this.Evt._Paging.next;
			btnNextSpan.appendChild(btn_next);
		} else {
			btnNextSpan.innerHTML = this.btnNextPageHtml;
			btnNextSpan.onclick = this.Evt._Paging.next;
		}
		
		if(this.btnPrevPageHtml==null)
		{// Previous button
			var btn_prev = tf_CreateElm( this.fltTypeInp,['id',this.prfxBtnPrev+this.id],
				['type','button'],['value',this.btnPrevPageText],['title','Previous'] );
			btn_prev.className = this.btnPageCssClass;
			btn_prev.onclick = this.Evt._Paging.prev;
			btnPrevSpan.appendChild(btn_prev);
		} else { 
			btnPrevSpan.innerHTML = this.btnPrevPageHtml;
			btnPrevSpan.onclick = this.Evt._Paging.prev;
		}
		
		if(this.btnLastPageHtml==null)
		{// Last button
			var btn_last = tf_CreateElm( this.fltTypeInp,['id',this.prfxBtnLast+this.id],
				['type','button'],['value',this.btnLastPageText],['title','Last'] );
			btn_last.className = this.btnPageCssClass;
			btn_last.onclick = this.Evt._Paging.last;
			btnLastSpan.appendChild(btn_last);
		} else { 
			btnLastSpan.innerHTML = this.btnLastPageHtml;
			btnLastSpan.onclick = this.Evt._Paging.last;
		}
		
		if(this.btnFirstPageHtml==null)
		{// First button
			var btn_first = tf_CreateElm( this.fltTypeInp,['id',this.prfxBtnFirst+this.id],
				['type','button'],['value',this.btnFirstPageText],['title','First'] );
			btn_first.className = this.btnPageCssClass;
			btn_first.onclick = this.Evt._Paging.first;
			btnFirstSpan.appendChild(btn_first);
		} else { 
			btnFirstSpan.innerHTML = this.btnFirstPageHtml;
			btnFirstSpan.onclick = this.Evt._Paging.first;
		}			
	}//if this.hasPagingBtns
	
	// paging elements (buttons+drop-down list) are added to defined element
	if(this.pagingTgtId==null) this.SetTopDiv();
	var targetEl = ( this.pagingTgtId==null ) ? this.mDiv : tf_Id( this.pagingTgtId );
	
	/***	if paging previously removed this prevents IE memory leak with removeChild 
			used in RemovePaging method. For more info refer to
			http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2840253&SiteID=1	***/
	if ( targetEl.innerHTML!='' ) targetEl.innerHTML = '';
	/*** ***/
	
	targetEl.appendChild(btnPrevSpan);
	targetEl.appendChild(btnFirstSpan);
	
	var pgBeforeSpan = tf_CreateElm( 'span',['id',this.prfxPgBeforeSpan+this.id] );
	pgBeforeSpan.appendChild( tf_CreateText(' Page ') );
	pgBeforeSpan.className = this.nbPgSpanCssClass;
	targetEl.appendChild(pgBeforeSpan);
	targetEl.appendChild(slcPages);
	var pgAfterSpan = tf_CreateElm( 'span',['id',this.prfxPgAfterSpan+this.id] );
	pgAfterSpan.appendChild( tf_CreateText(' of ') );
	pgAfterSpan.className = this.nbPgSpanCssClass;
	targetEl.appendChild(pgAfterSpan)
	var pgspan = tf_CreateElm( 'span',['id',this.prfxPgSpan+this.id] );
	pgspan.className = this.nbPgSpanCssClass;
	pgspan.appendChild( tf_CreateText(' '+this.nbPages+' ') );
	targetEl.appendChild(pgspan);
	targetEl.appendChild(btnLastSpan);
	targetEl.appendChild(btnNextSpan);
	this.pagingSlc = tf_Id(this.prfxSlcPages+this.id); //to be easily re-used
	
	// if this.rememberGridValues==true this.SetPagingInfo() is called
	// in ResetGridValues() method
	if( !this.rememberGridValues || this.isPagingRemoved )
		this.SetPagingInfo();
	if( !this.fltGrid )
	{
		this.ValidateAllRows();
		this.SetPagingInfo(this.validRowsIndex);
	}
		
	this.pagingBtnEvents = this.Evt._Paging;
	this.isPagingRemoved = false;
}

TF.prototype.RemovePaging = function()
/*====================================================
	- Removes paging elements
=====================================================*/
{
	if(!this.hasGrid) return;
	if( this.pagingSlc==null ) return;
	var btnNextSpan, btnPrevSpan, btnLastSpan, btnFirstSpan;// btns containers
	var pgBeforeSpan, pgAfterSpan, pgspan;
	btnNextSpan = tf_Id(this.prfxBtnNextSpan+this.id);
	btnPrevSpan = tf_Id(this.prfxBtnPrevSpan+this.id);
	btnLastSpan = tf_Id(this.prfxBtnLastSpan+this.id);
	btnFirstSpan = tf_Id(this.prfxBtnFirstSpan+this.id);
	pgBeforeSpan = tf_Id(this.prfxPgBeforeSpan+this.id);//span containing 'Page' text
	pgAfterSpan = tf_Id(this.prfxPgAfterSpan+this.id);//span containing 'of' text
	pgspan = tf_Id(this.prfxPgSpan+this.id);//span containing nb of pages
	
	this.pagingSlc.parentNode.removeChild(this.pagingSlc);
	
	if( btnNextSpan!=null )
		btnNextSpan.parentNode.removeChild( btnNextSpan );

	if( btnPrevSpan!=null )
		btnPrevSpan.parentNode.removeChild( btnPrevSpan );

	if( btnLastSpan!=null )
		btnLastSpan.parentNode.removeChild( btnLastSpan );

	if( btnFirstSpan!=null )
		btnFirstSpan.parentNode.removeChild( btnFirstSpan );

	if( pgBeforeSpan!=null )
		pgBeforeSpan.parentNode.removeChild( pgBeforeSpan );

	if( pgAfterSpan!=null )
		pgAfterSpan.parentNode.removeChild( pgAfterSpan );

	if( pgspan!=null )
		pgspan.parentNode.removeChild( pgspan );
	
	this.pagingBtnEvents = null;	
	this.pagingSlc = null;
	this.isPagingRemoved = true;
}

TF.prototype.SetPagingInfo = function( validRows )
/*====================================================
	- calculates page # according to valid rows
	- refreshes paging select according to page #
	- Calls GroupByPage method
=====================================================*/
{
	var row = this.tbl.rows;
	var mdiv = ( this.pagingTgtId==null ) ? this.mDiv : tf_Id( this.pagingTgtId );
	var pgspan = tf_Id(this.prfxPgSpan+this.id);
	
	if( validRows!=undefined ) this.validRowsIndex = validRows;//stores valid rows index
	else 
	{
		this.validRowsIndex = [];//re-sets valid rows index

		for(var j=this.refRow; j<this.nbRows; j++)//counts rows to be grouped 
		{
			if(!row[j]) continue;
			var isRowValid = row[j].getAttribute('validRow');
			if(isRowValid=='true' || isRowValid==null)
					this.validRowsIndex.push(j);
		}//for j
	}

	this.nbPages = Math.ceil( this.validRowsIndex.length/this.pagingLength );//calculates nb of pages
	pgspan.innerHTML = this.nbPages; //refresh page nb span 
	if(this.pageSelectorType==this.fltTypeSlc) 
		this.pagingSlc.innerHTML = '';//select clearing shortcut
	
	if( this.nbPages>0 )
	{
		mdiv.style.visibility = 'visible';
		if(this.pageSelectorType==this.fltTypeSlc)
			for(var z=0; z<this.nbPages; z++)
			{
				var currOpt = new Option((z+1),z*this.pagingLength,false,false);
				this.pagingSlc.options[z] = currOpt;
			}
		else this.pagingSlc.value = this.currentPageNb; //input type
		
	} else {/*** if no results paging select and buttons are hidden ***/
		mdiv.style.visibility = 'hidden';
	}
	this.GroupByPage( this.validRowsIndex );
}

TF.prototype.GroupByPage = function( validRows )
/*====================================================
	- Displays current page rows
=====================================================*/
{
	var row = this.tbl.rows;
	var paging_end_row = parseInt( this.startPagingRow ) + parseInt( this.pagingLength );
	
	if( validRows!=undefined ) this.validRowsIndex = validRows;//stores valid rows index

	for(h=0; h<this.validRowsIndex.length; h++)
	{//this loop shows valid rows of current page
		if( h>=this.startPagingRow && h<paging_end_row )
		{
			var r = row[ this.validRowsIndex[h] ];
			if(r.getAttribute('validRow')=='true' || r.getAttribute('validRow')==undefined)
				r.style.display = '';
			if(this.alternateBgs) this.SetRowBg(this.validRowsIndex[h],h);
		} else {
			row[ this.validRowsIndex[h] ].style.display = 'none';
			if(this.alternateBgs) this.RemoveRowBg(this.validRowsIndex[h]);
		}
	}
	
	this.nbVisibleRows = this.validRowsIndex.length;
	this.isStartBgAlternate = false;
	this.ApplyGridProps();//re-applies filter behaviours after filtering process
}
	
TF.prototype.SetPage = function( cmd )
/*====================================================
	- If paging set true shows page according to
	param value (string or number):
		- strings: 'next','previous','last','first' or
		- number: page number
=====================================================*/
{
	if( this.hasGrid && this.paging )
	{
		var btnEvt = this.pagingBtnEvents, cmdtype = typeof cmd;
		if(cmdtype=='string')
		{
			switch(cmd.tf_LCase())
			{
				case 'next':
					btnEvt.next();
				break;
				case 'previous':
					btnEvt.prev();
				break;
				case 'last':
					btnEvt.last();
				break;
				case 'first':
					btnEvt.first();
				break;
				default:
					btnEvt.next();
				break;
			}//switch
		}
		if(cmdtype=='number') this.ChangePage( (cmd-1) );
	}// this.hasGrid 
}

TF.prototype.SetResultsPerPage = function()
/*====================================================
	- Generates results per page select + label
=====================================================*/
{
	if(!this.hasGrid && !this.isFirstLoad) return;
	if( this.resultsPerPageSlc!=null || this.resultsPerPage==null ) return;
	
	//Change nb results per page event
	if(!this.Evt._OnSlcResultsChange)
	{
		var o = this;
		this.Evt._OnSlcResultsChange = function()
		/*====================================================
			- onchange event for results per page select
		=====================================================*/
		{
			o.ChangeResultsPerPage();
			this.blur();
			//ie only: blur is not enough...
			if(this.parentNode && tf_isIE) 
				this.parentNode.focus();
		}
	}
	
	var slcR = tf_CreateElm( this.fltTypeSlc,['id',this.prfxSlcResults+this.id] );
	slcR.className = this.resultsSlcCssClass;
	var slcRText = this.resultsPerPage[0], slcROpts = this.resultsPerPage[1];
	var slcRSpan = tf_CreateElm( 'span',['id',this.prfxSlcResultsTxt+this.id] );
	slcRSpan.className = this.resultsSpanCssClass;
	
	// results per page select is added to defined element
	if(this.resultsPerPageTgtId==null) this.SetTopDiv();
	var targetEl = ( this.resultsPerPageTgtId==null ) ? this.rDiv : tf_Id( this.resultsPerPageTgtId );
	slcRSpan.appendChild(tf_CreateText(slcRText));
	targetEl.appendChild(slcRSpan);
	targetEl.appendChild(slcR);
	
	this.resultsPerPageSlc = tf_Id(this.prfxSlcResults+this.id);
	
	for(var r=0; r<slcROpts.length; r++)
	{
		var currOpt = new Option(slcROpts[r],slcROpts[r],false,false);
		this.resultsPerPageSlc.options[r] = currOpt;
	}
	slcR.onchange = this.Evt._OnSlcResultsChange;
}

TF.prototype.RemoveResultsPerPage = function()
/*====================================================
	- Removes results per page select + label
=====================================================*/
{
	if(!this.hasGrid) return;
	if( this.resultsPerPageSlc==null || this.resultsPerPage==null ) return;
	var slcR, slcRSpan;
	slcR = this.resultsPerPageSlc;
	slcRSpan = tf_Id( this.prfxSlcResultsTxt+this.id );
	if( slcR!=null )
		slcR.parentNode.removeChild( slcR );
	if( slcRSpan!=null )
		slcRSpan.parentNode.removeChild( slcRSpan );
	this.resultsPerPageSlc = null;
}

TF.prototype.ChangePage = function( index )
{
	this.EvtManager(this.Evt.name.changepage,{ pgIndex:index });
}
TF.prototype._ChangePage = function( index )
/*====================================================
	- Changes page
	- Param:
		- index: option index of paging select 
		(numeric value)
=====================================================*/
{
	if( !this.paging ) return;
	if( index==undefined ) 
		index = (this.pageSelectorType==this.fltTypeSlc) ? 
			this.pagingSlc.options.selectedIndex : (this.pagingSlc.value-1);
	if( index>=0 && index<=(this.nbPages-1) )
	{
		this.currentPageNb = parseInt(index)+1;
		if(this.pageSelectorType==this.fltTypeSlc)
			this.pagingSlc.options[index].selected = true;
		else
			this.pagingSlc.value = this.currentPageNb;

		if( this.rememberPageNb ) this.RememberPageNb( this.pgNbCookie );
		this.startPagingRow = (this.pageSelectorType==this.fltTypeSlc)
			? this.pagingSlc.value : (index*this.pagingLength);
		this.GroupByPage();
	}
}

TF.prototype.ChangeResultsPerPage = function()
{
	this.EvtManager(this.Evt.name.changeresultsperpage);
}
TF.prototype._ChangeResultsPerPage = function()
/*====================================================
	- calculates rows to be displayed in a page
	- method called by nb results per page select
=====================================================*/
{
	if( !this.paging ) return;
	var slcR = this.resultsPerPageSlc;
	var slcPagesSelIndex = (this.pageSelectorType==this.fltTypeSlc) 
		? this.pagingSlc.selectedIndex : parseInt(this.pagingSlc.value-1);
	this.pagingLength = parseInt(slcR.options[slcR.selectedIndex].value);
	this.startPagingRow = this.pagingLength*slcPagesSelIndex;

	if( !isNaN(this.pagingLength) )
	{
		if( this.startPagingRow>=this.nbFilterableRows )
			this.startPagingRow = (this.nbFilterableRows-this.pagingLength);
		this.SetPagingInfo();

		if(this.pageSelectorType==this.fltTypeSlc)
		{
			var slcIndex = (this.pagingSlc.options.length-1<=slcPagesSelIndex ) 
							? (this.pagingSlc.options.length-1) : slcPagesSelIndex;
			this.pagingSlc.options[slcIndex].selected = true;
		}
		if( this.rememberPageLen ) this.RememberPageLength( this.pgLenCookie );
	}//if isNaN
}

TF.prototype.ResetPage = function( name )
{
	this.EvtManager(this.Evt.name.resetpage);
}
TF.prototype._ResetPage = function( name )
/*==============================================
	- re-sets page nb at page re-load
	- Params:
		- name: cookie name (string)
===============================================*/
{
	var pgnb = tf_ReadCookie(name); //reads the cookie
	if( pgnb!='' ) 
		this.ChangePage((pgnb-1));
}

TF.prototype.ResetPageLength = function( name )
{
	this.EvtManager(this.Evt.name.resetpagelength);
}
TF.prototype._ResetPageLength = function( name )
/*==============================================
	- re-sets page length at page re-load
	- Params:
		- name: cookie name (string)
===============================================*/
{
	if(!this.paging) return;
	var pglenIndex = tf_ReadCookie(name); //reads the cookie
	
	if( pglenIndex!='' )
	{
		this.resultsPerPageSlc.options[pglenIndex].selected = true;
		this.ChangeResultsPerPage();
	}
}

TF.prototype.AddPaging = function(filterTable)
/*====================================================
	- Adds paging feature if filter grid bar is 
	already set
	- Param(s):
		- execFilter: if true table is filtered 
		(boolean)
=====================================================*/
{
	if( !this.hasGrid || this.paging ) return;
	this.paging = true; 
	this.isPagingRemoved = true; 
	this.SetPaging();
	if(filterTable) this.Filter();
}

