function SEARCH_Controller(target,url,searchstringname,minwaittime)
	{
	//define global vars
	if (typeof(this.target) == 'undefined')
		{
		this.target = target;
		}
	if (typeof(this.url) == 'undefined')
		{
		this.url = url;
		}
	if (typeof(this.searchstringname) == 'undefined')
		{
		this.searchstringname = searchstringname;
		}
	if (typeof(minwaittime) == 'undefined')
		{
		//only search every 250 ms
		this.minwaittime = 250;
		}
	else
		{
		this.minwaittime = minwaittime;
		}
	//set vars to false, they will be overwritten by the functions
	this.searchstring = false;
	this.optional = false;
	this.intervalID = false;

	//constructor define all instances of the 'class'
	SEARCH_Controller.prototype.searchRequest = searchRequest;
	SEARCH_Controller.prototype.startProcess = startProcess;
	SEARCH_Controller.prototype.runProcess = runProcess;

	//initial function if you call a new SEARCH_Controller
	function searchRequest(searchstring,optional)
		{
		this.searchstring = searchstring.value;
		if (typeof(optional) != 'undefined')
			{
			this.optional = optional;
			}
		if (!this.intervalID)
			{
			this.runProcess();
			this.startProcess();
			}
		}
	//start the intevall if this.minwaittime is timed out the runProcess() will run a request
	function startProcess()
		{
		var _this = this;
		//do not run the request on every keypress
		this.intervalID = window.setInterval(function(){_this.runProcess();},this.minwaittime);
		}
	//abort the old request a run a new one 
	function runProcess()
		{
		if (this.searchstring)
			{
			if (this.clientsearch)
				{
				this.clientsearch.abortRequest();
				}
			//create a new request, the old one should be aborted
			this.clientsearch = new SEARCH_Client(this.target,this.url,this.searchstringname,this.searchstring,this.optional);
			//reset options
			this.searchstring = false;
			this.optional = false;
			//run the request!
			this.clientsearch.runRequest();
			}
		}
	}

function SEARCH_Client(target,url,searchstringname,searchstring,optional)
	{
	//abort request after 10 seconds
	this.timeout = 10000;
	//hide loading bar after 10 seconds
	this.hideloadingtime = 10000;
	
	//define global vars
	this.target = target;
	this.url = url;
	this.searchstringname = searchstringname;
	this.searchstring = searchstring;
	if (typeof(optional) != 'undefined')
		{
		this.optional = optional;
		}

	//constructor define all instances of the 'class'
	SEARCH_Client.prototype.makeHttpRequest = makeHttpRequest;
	SEARCH_Client.prototype.testRequest = testRequest;
	SEARCH_Client.prototype.abortRequest = abortRequest;
	SEARCH_Client.prototype.hideLOADING = hideLOADING;
	SEARCH_Client.prototype.unhideLOADING = unhideLOADING;
	SEARCH_Client.prototype.runRequest = runRequest;
	SEARCH_Client.prototype.searchCallBack = searchCallBack;

	//create a XMLHttpRequest
	function makeHttpRequest()
		{
		try
			{
			this.req = new XMLHttpRequest();
			}
		catch(Error)
			{
			try
				{
				this.req = new ActiveXObject("Microsoft.XMLHTTP");
				}
			catch(Error)
				{
				try
					{
					this.req = new ActiveXObject("MSXML2.XMLHTTP");
					}
				catch(Error)
					{
					this.req = false;
					}
				}
			}
		return this.req;
		}
	//check if this.req is in transmission mode, if readyState is 1,2 or 3 it will return true 
	function testRequest()
		{
		if (this.req)
			{
			switch (this.req.readyState)
				{
				case 1:
				case 2:
				case 3:
				return true;
				break;
				default:
				return false;
				break;
				}
			}
		else
			{
			return false;
			}
		}
	//send the abort command to the request
	function abortRequest()
        {
		if (this.testRequest())
			{
			this.req.abort();
	        if (this.timeoutabort)
	        	{
				window.clearTimeout(this.timeoutabort);
	        	}
            }
        }
	//hide the loading bar
	function hideLOADING()
		{
		document.getElementById('AJAX_LOADING').style.display = 'none';
		}
	//show the loading bar
	function unhideLOADING()
		{
		var _this = this;
		document.getElementById('AJAX_LOADING').style.display = 'inline';
		//reset the timeout
		if (this.timeouthide)
			{
			window.clearTimeout(this.timeouthide);
			}
		//set a time out to hide the searchbar after a few seconds
    	this.timeouthide = window.setTimeout(function(){_this.hideLOADING();},this.hideloadingtime);
		}

	//run the XMLHttpRequest
	function runRequest()
		{
		if (!this.req)
			{
			//make XMLHttpRequest
			this.makeHttpRequest();
			}
		var _this = this;
		//abort if this.searchstring is not defined
		if (typeof(this.searchstring) == 'undefined')
			{
			//abort last request
			this.abortRequest();
			//hide LOADING bar
			this.hideLOADING();
			return false;
			}
		if (this.optional)
			{
			// add optional option to the uri
			this.uri = this.url + "&" + this.searchstringname + "=" + this.searchstring + "&optional=" + this.optional;
			}
		else
			{
			//build the get uri
			this.uri = this.url + "&" + this.searchstringname + "=" + this.searchstring;
			}
		if (this.req)
			{
			this.req.open('GET',this.uri,true);
			this.req.onreadystatechange = function() { _this.searchCallBack(); }
			this.req.send(null);
   			this.timeoutabort = window.setTimeout(function(){_this.abortRequest();},this.timeout);
			}
		}

	//calback function to display the results
	function searchCallBack()
		{
		try
			{
			//only show readyState 4 (transmission completed)
			switch (this.req.readyState)
				{
				case 4:
					//only show HTTP OK
					if (this.req.status == 200)
						{
						window.clearTimeout(this.timeoutabort);
						//display responseText in target
						document.getElementById(this.target).style.display = 'inline';
						document.getElementById(this.target).innerHTML = this.req.responseText;
						//hide LOADING bar
						this.hideLOADING();
						}
				break;
				default:
					//display LOADING bar
					this.unhideLOADING();
				}
			}
		catch (e)
			{
			//error report of because of some browser problems
			alert (e);
			}
		}

	}