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";

 this.init = function(searchURL, formname, queryParamName, divLayername, instanceName, debugMode) {
  pSearchURL      = searchURL;
  pFormname       = formname;
  pQueryParamName = queryParamName;
  pLayerName      = divLayername;
  pInstanceName   = instanceName;
  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];
  pQueryInput.onkeyup     = handleKeyPress;
  pQueryInput.onfocus     = showLayer;
  pQueryInput.onblur      = hideLayer;
  document[pFormname].onsubmit = handleSubmit;
 }

 this.setHighlightColors = function(highlighBackgroundColor, highlighTextColor) {
  pHighlightBgColor      = highlighBackgroundColor;
  pHighlightTextColor    = highlighTextColor;
 }

 this.setStandardColors = function(standardBackgroundColor, standardTextColor) {
  pStandardBgColor      = standardBackgroundColor;
  pStandardTextColor    = standardTextColor;
 }

 this.setCellspacing = function(cellspacing) {
  pCellSpacing = cellspacing;
 }

 function handleSubmit() {
  if (pSuggest[pCurrentSelection] != undefined) {
   if (pSuggest[pCurrentSelection].split('###')[1] == "Kategorie") {
    document[pFormname]["filterkategorie"].value = "__" + pSuggest[pCurrentSelection].split('###')[0] + "__";
    document[pFormname][pQueryParamName].value = "";
   } else {
    document[pFormname][pQueryParamName].value = pSuggest[pCurrentSelection].split('###')[0];
   }
  }
 }

 this.handleClick = function() {
  if (pSuggest[pCurrentSelection] != undefined) {
   if (pSuggest[pCurrentSelection].split('###')[1] == "Kategorie") {
    document[pFormname]["filterkategorie"].value = "__" + pSuggest[pCurrentSelection].split('###')[0] + "__";
    document[pFormname][pQueryParamName].value = "";
    document[pFormname].submit();
   } else {
    document[pFormname][pQueryParamName].value = pSuggest[pCurrentSelection].split('###')[0];
    document[pFormname].submit();
   }
  }
 }

 this.handleMouseOver = function(pos) {
  var tblCell = getTableCell(pos);
  unmarkAll();
  if (tblCell != null) {
   highlightSuggest(tblCell);
   pCurrentSelection = pos;
  }
 }

 this.handleMouseOut = function(pos) {
  var tblCell = getTableCell(pos);
  if (tblCell != null) {
   unmarkSuggest(tblCell);
   pCurrentSelection = -1
  }
 }

 function handleKeyPress(evt) {
  evt = (evt) ? evt : ((event) ? event : null);
  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 tblCell = getTableCell(pos);
   if (tblCell != null) {
    unmarkAll();
    highlightSuggest(tblCell);
    pCurrentSelection = pos;
   }
  }

  var query = pQueryInput.value;
  pQueryInput.value = "";
  pQueryInput.focus();
  pQueryInput.value = query;
 }

 function startAjax() {
  var query = pQueryInput.value;
  var requestURL = pSearchURL + pQueryParamName + "=" + query;
  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 outputText = '<table class="' + pLayerName + '" 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("###");
   var count = pSuggestParts[1].split(" ")[0];
   
   outputText += '<tr>';
   //outputText += '<td nowrap="nowrap" id="' + pLayerName + '_' + i + '" style="background-color: ' + pStandardBgColor + '; color: ' + pStandardTextColor + ';padding: 2 2 2 0px;" onMouseOver="' + pInstanceName + '.handleMouseOver(' + i + ');" onMouseOut="' + pInstanceName + '.handleMouseOut(' + i + ');">' + pSuggestParts[0] + '</td>';
   outputText += '<td id="' + pLayerName + '_' + i + '" class="suggest" onMouseOver="' + pInstanceName + '.handleMouseOver(' + i + ');" onMouseOut="' + pInstanceName + '.handleMouseOut(' + i + ');">' + pSuggestParts[0] + '</td>';
   //outputText += '<td style="background-color: ' + pStandardBgColor + '">&nbsp;&nbsp;</td>';
   //outputText += '<td nowrap="nowrap" align="right" style="background-color: ' + pStandardBgColor + '; color: ' + pStandardTextColor + ';padding: 2 2 2 0px;" width="30%">' + pSuggestParts[1] + '</td>';
   outputText += '<td class="account">[ ' + count + ' ]</td>';
   outputText += '</tr>';
  }
  outputText += '</table>';
  //alert(outputText)
  if (pSuggest.length >= 1) {
   showLayer();
   pLayer.innerHTML = outputText;
  } else {
   hideLayer();
   pLayer.innerHTML = "";
  }
 }

 function highlightSuggest(tblCell) {
  tblCell.style.backgroundColor	= pHighlightBgColor;
  tblCell.style.color = pHighlightTextColor;
 }

 function unmarkSuggest(tblCell) {
  tblCell.style.backgroundColor	= pStandardBgColor;
  tblCell.style.color = pStandardTextColor;
 }

 function unmarkAll() {
  var tblCell;
  for (var i in pSuggest) {
   tblCell = getTableCell(i);
   if (tblCell != null) {
    unmarkSuggest(tblCell);
   }
  }
 }

 function getTableCell(pos) {
  var tblCell;
  tblCell = document.getElementById(pLayerName + "_" + pos);
  return tblCell;
 }

}
