
function Searcher(tableId,maxToShow,selectable,mutlipleSelect,noCursor,
rowTemplateCursor,
rowTemplateCursorSelected,
rowTemplateOdd,
rowTemplateEven,
rowTemplateOddSelected,
rowTemplateEvenSelected,
rowHead,
rowTail,
tablePre,
tablePost,
focusBackId
) {
	function addColumn(type) {
		this.types.push(type);
	}
	
	function addRow(array) {
		this.rows.push(array);
	}
	
	function searchOnColumn(nr,text,caseInsensetive) {
		this.currentFramePosition=0;
		this.currentCursorPosition=0;
	
		var i,j;
		var f=new Array();
		var fNr=new Array();
		for(i=0;i<this.rows.length;i++) {
			var match=false;
			var result=new Array();
			for(j=0;j<this.types.length;j++) {
				if( j==(nr-1) ) {
					var m=matchStrings(this.rows[i][j],text,caseInsensetive,'<b>','</b>');
					if( m==null )
						result.push(this.rows[i][j]);
					else {
						result.push(m);
						match=true;
					}
				}
				else {
					result.push(this.rows[i][j]);
				}
			}
			
			if( match ) 
			{
				f.push(result);
				fNr.push(i);
			}
		}
		
		
		this.filteredData=f;
		this.filteredDataMap=fNr;
		this.selectedData=new Array();
		this.makeTable();
		
		return f.length>0;
	}
	function searchOnTextColumns(text,caseInsensetive) {
	
	
		this.currentFramePosition=0;
		this.currentCursorPosition=0;

		var i,j;
		var f=new Array();
		var fNr=new Array();
		for(i=0;i<this.rows.length;i++) {
			var match=false;
			var result=new Array();
			for(j=0;j<this.types.length;j++) {
				if( this.types[j]=='text' ) {
					var m=matchStrings(this.rows[i][j],text,caseInsensetive,'<b>','</b>');
					if( m==null )
						result.push(this.rows[i][j].replace(/</,'&lt;').replace(/>/,'&gt;'));
					else {
						result.push(m);
						match=true;
					}
				}
				else {
					result.push(this.rows[i][j].toString().replace(/</,'&lt;').replace(/>/,'&gt;'));
				}
			}
			
			if( match ) 
			{
				f.push(result);
				fNr.push(i);
			}
		}
		
		
		this.filteredData=f;
		this.filteredDataMap=fNr;
		this.selectedData=new Array();
		this.makeTable();
		
		return f.length>0;
	}
	
	function makeTable() {
		var rws=this.filteredData;
	
		var i;
		var f='';
		
		if( (this.currentFramePosition+this.maxToshow)>rws.length )
			this.currentFramePosition=rws.length-maxToShow;
			
		if( this.currentFramePositon<0 )
			this.currentFramePosition;

		var n=0;
		for(i=this.currentFramePosition;i<rws.length && i<(this.maxToShow+this.currentFramePosition);i++) {
			
			var row;

			if( this.currentCursorPosition==n && !this.noCursor )
			{

				if( this.selectedData[i] )
					row=this.makeRow(rowTemplateCursorSelected,rws[i],i);
				else
					row=this.makeRow(rowTemplateCursor,rws[i],i);
			}
			else
			{
				if( this.selectedData[i] )
					row=this.makeRow((n%2)==0?rowTemplateOddSelected:rowTemplateEvenSelected,rws[i],i);
				else
					row=this.makeRow((n%2)==0?rowTemplateOdd:rowTemplateEven,rws[i],i);
			}
			f=f+row;
			n++;
		}

		var head=this.tablePre;
		var tail=this.tablePost;
		
		if( this.currentFramePosition>0 )
			head+=this.rowHead;
		if( (this.currentFramePosition+this.maxToShow)<this.filteredData.length )
			tail=this.rowTail+tail;

		head=this.replaceIt(head,'{found}',this.filteredData.length);
		tail=this.replaceIt(tail,'{found}',this.filteredData.length);


		document.getElementById(this.tableId).innerHTML=head+f+tail;
	}
	
	function makeRow(template,values,nr) {
		var j;
		var row=template;
		for(j=0;j<values.length;j++) {
			var pattern="{col"+(j+1)+"}";
			var val=values[j];

			row=replaceIt(row,pattern,val);
		}
		
		row=row.replace(/{nr}/g,(nr+1));

		return row;
	}		
	
	function toLower(text) {
		text=text.toLowerCase();
		text=text.replace(/¥/,"¹");
		text=text.replace(/Æ/,"æ");
		text=text.replace(/Ê/,"ê");
		text=text.replace(/£/,"³");
		text=text.replace(/Ó/,"ó");
		text=text.replace(/Ñ/,"ñ");
		text=text.replace(/Œ/,"œ");
		text=text.replace(/¯/,"¿");
		text=text.replace(//,"Ÿ");
		return text;
	}
	
	function matchStrings(text,search,caseInsensetive,startTag,stopTag) {
		var searchLower=search;
		var textLower=text;
		var re;
		
		if( caseInsensetive ) {
			searchLower=toLower(searchLower);
			textLower=toLower(textLower);
		}

		var re=new RegExp("(.*?)([^a-zA-Z]|^)"+searchLower+"(.*)");
		var m=re.exec(textLower);
		if( m==null )
			return null;
		
		if( !caseInsensetive )
			return (m[1]+m[2]).replace(/</,'&lt;').replace(/>/,'&gt;')+startTag+search.replace(/</,'&lt;').replace(/>/,'&gt;')+stopTag+m[3].replace(/</,'&lt;').replace(/>/,'&gt;');
		
		
		var l1=m[1].length+m[2].length;
		var l2=search.length;
			
		return (text.substr(0,l1)).replace(/</,'&lt;').replace(/>/,'&gt;')+startTag+text.substr(l1,l2).replace(/</,'&lt;').replace(/>/,'&gt;')+stopTag+text.substring(l1+l2).replace(/</,'&lt;').replace(/>/,'&gt;');
	}
	
	
	function replaceIt(sString, sReplaceThis, sWithThis) {
		if (sReplaceThis != "" && sReplaceThis != sWithThis) {
		var counter = 0;
		var start = 0;
		var before = "";
		var after = "";
		while (counter<sString.length) {
		start = sString.indexOf(sReplaceThis, counter);
		if (start == -1) {
		break;
		} else {
		before = sString.substr(0, start);
		after = sString.substr(start + sReplaceThis.length, sString.length);
		sString = before + sWithThis + after;
		counter = before.length + sWithThis.length;
		}
		}
		}
		return sString;
	}
	
	function movePgUp() {
		if( this.currentFramePosition>0 ) {
			this.currentCursorPosition=0;
			this.currentFramePosition-=this.maxToShow;
			if( this.currentFramePosition<0 )
				this.currentFramePosition=0;
			this.makeTable();
			return;
		}
		else
		{
			if( this.currentCursorPosition>0 )
			{
				this.currentCursorPosition=0;
				this.makeTable();
				return;
			}
		}
	}
	function movePgDown() {
		if( this.filteredData.length<this.maxToShow )
		{
			if( this.currentCursorPosition<(this.filteredData.length-1) )
			{
				this.currentCursorPosition=this.filteredData.length-1;
				this.currentFramePosition=0;
				this.makeTable();
				return;
			}
		}
		else
		{
			if( this.currentFramePosition<(this.filteredData.length-this.maxToShow) || this.currentCursorPosition<(this.maxToShow-1) ) {
				this.currentCursorPosition=this.maxToShow-1;
				this.currentFramePosition+=this.maxToShow;
				if( this.currentFramePosition>(this.filteredData.length-this.maxToShow) )
					this.currentFramePosition=this.filteredData.length-this.maxToShow;
				
				this.makeTable();
				return;
			}
	}
	}
	
		
	function moveHome() {
		if( this.currentCursorPosition>0 || this.currentFramePosition>0 ) {
			this.currentCursorPosition=0;
			this.currentFramePosition=0;
			this.makeTable();
			return;
		}
	}
	
	function moveEnd() {
		if( this.filteredData.length<this.maxToShow )
		{
			if( this.currentCursorPosition<(this.filteredData.length-1) )
			{
				this.currentCursorPosition=this.filteredData.length-1;
				this.currentFramePosition=0;
				this.makeTable();
				return;
			}
		}
		else
		if( this.currentCursorPosition<(this.maxToShow-1) || this.currentFramePosition<(this.filteredData.length-this.maxToShow) ) {
			this.currentCursorPosition=this.maxToShow-1;
			this.currentFramePosition=this.filteredData.length-this.maxToShow;
			this.makeTable();
			return;
		}
	}
	
	function moveUp() {
		if( this.noCursor )
			return;
		if( this.currentCursorPosition>0 ) {
			this.currentCursorPosition--;
			this.makeTable();
			return;
		}
		
		if( this.currentFramePosition>0 ) {
			this.currentFramePosition--;
			this.makeTable();
			return;
		}
	}
	function moveDown() {
		if( this.noCursor )
			return;
		if( this.currentCursorPosition<(this.maxToShow-1) && this.currentCursorPosition<(this.filteredData.length-1) ) {
			this.currentCursorPosition++;
			this.makeTable();
			return;
		}
		
		if( (this.currentFramePosition+this.maxToShow)<(this.filteredData.length-1) ) {
			this.currentFramePosition++;
			this.makeTable();
			return;
		}
	}
	
	function selectRow(nr,selected) {
		if( !this.selectable || this.noCursor )
			return;
		if( nr==null )
			nr=this.currentCursorPosition+this.currentFramePosition;
		if( selected==null )
			selected=!this.selectedData[nr];
			
		if( !this.mutlipleSelect )
		{
			var i;
			for(i=0;i<this.selectedData.length;i++)
				this.selectedData[i]=false;
		}
			

		this.selectedData[nr]=selected;
		this.makeTable();
		
		if( this.focusBackId )
			document.getElementById(this.focusBackId).focus();
		
		return selected;
	}


	function setCursorPosition(nr) {
		if( this.currentCursorPosition==(nr-this.currentFramePosition) )
			return;
		this.currentCursorPosition=nr-this.currentFramePosition;
		this.makeTable();
	}
	
	function getSelectedValue(colNr) {
		if( this.filteredData.length==0 )
			return "";
			
			
		var row=this.rows[this.filteredDataMap[this.currentCursorPosition+this.currentFramePosition]];
		
		if( colNr==null )
		{
			var i,r='',sep='';
			
			for(i=0;i<row.length;i++)
			{
				r+=sep+row[i];
				sep=' ';
			}
			return r;
		}
		
		if( row.length<=colNr )
			return "";
			
		return row[colNr];	
	}
	
	

	
	this.moveUp=moveUp;
	this.moveDown=moveDown;
	this.moveHome=moveHome;
	this.moveEnd=moveEnd;
	this.movePgUp=movePgUp;
	this.movePgDown=movePgDown;
	
	this.toLower=toLower;
	this.addColumn=addColumn;
	this.addRow=addRow;
	this.searchOnColumn=searchOnColumn;
	this.searchOnTextColumns=searchOnTextColumns;
	this.makeTable=makeTable;
	this.makeRow=makeRow;
	this.matchStrings=matchStrings;
	
	this.rows=new Array();
	this.types=new Array();
	this.tableId=tableId;
	
	this.selectable=selectable;
	this.mutlipleSelect=mutlipleSelect;
	this.maxToShow=maxToShow;
	
	this.currentFramePosition=0;
	this.currentTopPosition=0;
	
	
	this.setCursorPosition=setCursorPosition;
	this.selectRow=selectRow;
	
	this.focusBackId=focusBackId;
	this.tablePre=tablePre;
	this.tablePost=tablePost;
	
	this.getSelectedValue=getSelectedValue;
	
	this.rowHead=rowHead;
	this.rowTail=rowTail;
	
	this.noCursor=noCursor;
	this.replaceIt=replaceIt;
	
}



function SearcherScroller(searcher,divId,inputId,enterMode,staticPosition,enterCallback) {
	this.searcher=searcher;
	this.lastValue='';
	this.divId=divId;
	this.inputId=inputId;
	this.enterCallback=enterCallback;
	this.enterMode=enterMode;
	this.staticPosition=staticPosition;
	this.callback=callback;
	this.copyToInput=copyToInput;
	
	function callback() {
		this.enterCallback();
	}
	
	function copyToInput() {
		var val=this.searcher.getSelectedValue();
		document.getElementById(this.divId).style.display='none';
		this.lastValue=val;
		document.getElementById(this.inputId).value=val;
	}

	function doScroll(key) {

			if( key==33 )
				this.searcher.movePgUp();
			if( key==34 )
				this.searcher.movePgDown();
			if( key==36 )
				this.searcher.moveHome();
			if( key==35 )
				this.searcher.moveEnd();
			if( key==38 )
				this.searcher.moveUp();
			if( key==40 )
				this.searcher.moveDown();
			if( key==27 && !this.staticPosition )
				document.getElementById(this.divId).style.display='none';
			if( key==13 )
			{

				if( document.getElementById(this.divId).style.display=='block' )
				{
					if( this.enterMode & 1 )
						this.enterCallback();
					if( this.enterMode & 2 )
						this.searcher.selectRow();
					
					if( this.enterMode & 4 )
						this.copyToInput();
				}
			}
	}

	this.doScroll=doScroll;
	
	function doSearch(text,colNr,force,forceStart) {
		if( this.lastValue==text && forceStart==null)
			return;
	
		
		this.lastValue=text;
		if( text=='' && !force ) 
		{
			document.getElementById(this.divId).style.display='none';
		}
		else
		{
			var result;
			if( colNr==null )
				result=mySearcher.searchOnTextColumns(text,true);
			else
				result=mySearcher.searchOnColumn(colNr,text,true);

			if( result )
			{

				if( !this.staticPosition )
				{
					var top=document.getElementById(this.inputId).offsetTop;
					var left=document.getElementById(this.inputId).offsetLeft;
					var height=document.getElementById(this.inputId).offsetHeight;
				
					document.getElementById(this.divId).style.top=top+height;
					document.getElementById(this.divId).style.left=left;
				}
				document.getElementById(this.divId).style.display='block';
			}
			else
				document.getElementById(this.divId).style.display='none';
		}
	}
	
	this.doSearch=doSearch;
}
