function FFSuggest() {
	
	var pRequest;
	var pLayer;
	var pDebug					= false;
	var pInstanceName			= "";
	var pSearchURL				= "";
	var pQueryParamName			= "";
	var pFormname 				= "";
	var pLayerName				= ""
	var pQueryInput;
	var pSuggest;
	var pLastQuery;
	var pCurrentSelection		= 0;
	var pCellSpacing			= 0;
	var pHighlightBgColor 		= "#3366CC";
	var pHighlightTextColor 	= "#FFFFFF";	
	var pStandardBgColor 		= "#FCFCFC";
	var pStandardTextColor 		= "#000000";
	var timestamp = 0;
	var pshowsuggestcount;
	
	this.init = function(searchURL, formname, queryParamName, divLayername, instanceName, debugMode, showsuggestcount) {
		pSearchURL		= searchURL;
		pFormname		= formname;
		pQueryParamName	= queryParamName;
		pLayerName		= divLayername;
		pInstanceName	= instanceName;
		pshowsuggestcount = showsuggestcount;
		pDebug			= debugMode;
		if (pSearchURL == "") {		
			if (pDebug) alert("no searchurl defined");
			return null;
		} else if (pInstanceName == "") {
			if (pDebug) alert("no instancename defined");
			return null;
		} else if (pFormname == "") {
			if (pDebug) alert("no formname defined");
			return null;
		} else if (pQueryParamName == "") {
			if (pDebug) alert("no queryparamname defined");
			return null;
		} else if (pLayerName == "") {
			if (pDebug) alert("need a layer for output");
		}
		pQueryInput = document[pFormname][pQueryParamName];
		if (pQueryInput != null)
		{
		    pQueryInput.onkeyup	= handleKeyDown;
		    pQueryInput.onfocus	= showLayer;		
		    pQueryInput.onblur	= hideLayer;
		}
		else if (pDebug) alert("document[pFormname][pQueryParamName] empty");
		document[pFormname].onsubmit = handleSubmit;
	}
	
	this.setCellspacing = function(cellspacing) {
		pCellSpacing = cellspacing;
	}
	
	function handleSubmit() 
	{
        if (pSuggest != undefined && pSuggest[pCurrentSelection] != undefined) {
          var query = pSuggest[pCurrentSelection].split('###')[0];
	        query = query.replace(/<!--[^->]*-->/,"");
	        if (pSuggest[pCurrentSelection].split('###')[1] == "Kategorie") {
		        document[pFormname]["filterkategorie"].value = "__" + query + "__";
		        document[pFormname][pQueryParamName].value = "";
	        }
	        else {
		        document[pFormname][pQueryParamName].value = query;
	        }
        }
	}
	
	this.handleClick = function() {
		if (pSuggest[pCurrentSelection] != undefined) {
			var query = pSuggest[pCurrentSelection].split('###')[0];
			query = query.replace(/<!--[^->]*-->/,"");
			if (pSuggest[pCurrentSelection].split('###')[1] == "Kategorie") 
			{
			  document[pFormname]["filterkategorie"].value = "__" + query + "__";
				document[pFormname][pQueryParamName].value = "";
				document[pFormname].submit();
			}
			else 
			{
				document[pFormname][pQueryParamName].value = query;
				document[pFormname].submit();
			}
		}
	}
	
	this.handleMouseOver = function(pos) {
		var tr = getTableTr(pos);
		unmarkAll();
		if (tr != null) {
		  highlightSuggest(tr);
			pCurrentSelection = pos;
		}
	}
	
	this.handleMouseOut = function(pos) {
		var tr = getTableTr(pos);	
		if (tr != null) {	 
		  unmarkSuggest(tr);
			pCurrentSelection = -1
		}
	}
	
	function handleKeyDown(evt) {
		evt = (evt) ? evt : ((event) ? event : null);
		if (evt.timeStamp - timestamp < 10) {
			return;
		}
		else {
			timestamp = evt.timeStamp;
		}

		var keyCode = evt.keyCode;
		if (keyCode == 38) {
			moveSelection("up")
		} else if (keyCode == 40) {
			moveSelection("down");
		} else {
			if (pQueryInput.value == "") {
				hideLayer();
				if (pLayer != null) pLayer.innerHTML = "";
				return null;
			}
			if (pLastQuery != pQueryInput.value) startAjax();
			pLastQuery = pQueryInput.value;			
		}
	}

	function moveSelection(direction) {
		var pos = pCurrentSelection;
		if (direction == "up")	pos--;
		else 					pos += 1;
		
		if (pos < 0) {
		  unmarkAll();
			pQueryInput.focus();
			pCurrentSelection	= -1;
		} else {
			var tr = getTableTr(pos);
			if (tr != null) {
			  unmarkAll();
				highlightSuggest(tr);
				pCurrentSelection = pos;
			}
		}
		
		var query = pQueryInput.value;
		pQueryInput.value = "";
		pQueryInput.focus();
		pQueryInput.value = query; 
	}
	
	function startAjax() {
	    var query = pQueryInput.value;
		var requestURL = pSearchURL + (pSearchURL.indexOf('?') > 0? "&":"?") + pQueryParamName + "=" + utfencode(query) + "&ajax=1";
		try {
			if( window.XMLHttpRequest ) {
				pRequest = new XMLHttpRequest();
			} else if( window.ActiveXObject ) {
				pRequest = new ActiveXObject( "Microsoft.XMLHTTP" );
			} else {
				if (pDebug) alert( "" );
			}
			
			pLayer = document.getElementById(pLayerName);
			if (pLayer != null) {
				if (query != "") {
					pRequest.open( "GET", requestURL, true );
					pRequest.onreadystatechange = callbackAjax;
					pRequest.send( null );
				} else {
					hideLayer();
				}
			} else {
				if (pDebug) alert( "no layer for output found" );
			}
		} catch( ex ) {
			hideLayer();
			if (ex == undefined) {
				if (pDebug) alert( "Error: " + ex.getmessage );
			} else {
				if (pDebug) alert( "Error: " + ex );
			}
		}
	}
	
	function hideLayer() {
		if (pLayer != null) {
			pLayer.style.display = "none";
		}
	}
	
	this.hideLayerOutsideCall = function() {
		if (pLayer != null) {
			pLayer.style.display = "none";
		}
	}
	
	function showLayer() {
		if (pLayer != null && pSuggest.length >= 1) {
			pLayer.style.display	= "block";
		}
	}
	
	function callbackAjax() {
		if (pRequest.readyState == 4) {
			if (pRequest.status != 200) {
				hideLayer();
				if (pDebug) alert( "Error (" + pRequest.status + "): " + pRequest.statusText );
			} else {
				handleResponse(pRequest.responseText);
			}
		}
  }
	
	function handleResponse(text) {
		pCurrentSelection = -1;
		pSuggest = new Array();
		pSuggest = text.split("\n");
		var outputText = '<table cellpadding="' + pCellSpacing + '" cellspacing="0" class="' + pLayerName + '" width="100%" border="0" onMouseDown="' + pInstanceName + '.handleClick();">';
		var pNewSuggest = new Array();
		for (var i in pSuggest) {
			var firstChar = pSuggest[i].charCodeAt(0);
			if (firstChar != 13 && firstChar != 10 && pSuggest[i].length >= 1) {
				pNewSuggest.push(pSuggest[i]);
			}
		}
		pSuggest = pNewSuggest;
		for (var i in pSuggest) {
			pSuggestParts = new Array();
			pSuggestParts = pSuggest[i].split("###");
			outputText += '<tr onMouseOver="' + pInstanceName + '.handleMouseOver(' + i + ');" onMouseOut="' + pInstanceName + '.handleMouseOut(' + i + ');" id="' + pLayerName + '_' + i + '"><td nowrap="nowrap" class="suggesttitle">' + pSuggestParts[0] + '</td>';
			if (pshowsuggestcount == '1')
			  outputText += '<td class="suggestprodnumber" align="right" nowrap="nowrap">' + pSuggestParts[1] + '</td>';
			outputText += '</tr>';				
		}
		outputText += '</table>';
		//alert(outputText)
		if (pSuggest.length >= 1) {
			showLayer();
			pLayer.innerHTML		= outputText;
		} else {
			hideLayer();
			pLayer.innerHTML		= "";
		}
	}
	
	function highlightSuggest(tr) {
		tr.setAttribute("class", "suggesthovered");
		tr.setAttribute("className", "suggesthovered"); //for IE
	}
	
	function unmarkSuggest(tr) {
		tr.setAttribute("class", "");
		tr.setAttribute("className", ""); //for IE
	}
	
	function unmarkAll() {
		var tr;
		for (var i in pSuggest) {
			tr = getTableTr(i);
			if (tr != null) {
				unmarkSuggest(tr);
			}
		}
	}
		
	function getTableTr(pos) {
		var tr;
		tr = document.getElementById(pLayerName + "_" + pos);
		return tr;
	}
	
	function utfencode(string)
	{
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";

		for (var n = 0; n < string.length; n++) 
		{

			var c = string.charCodeAt(n);

			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}
		}
		return escape(utftext);
	}
}