function FFSuggest() {

	var pDebug					= false;
	var pInstanceName			= '';
	var pSearchURL				= '';
	var pQueryParamName			= '';
	var pFormname 				= '';
	var pLayerName				= '';
	var pQueryInput;
	var pSuggest				= new Array();
	var pDeeplink				= new Array();
	var pLastQuery;
	var submitted				= false;
	var pShowImages				= false;

	var pSuggestImageClass 		= 'suggestImage';
	var pSuggestQueryClass 		= 'suggestTextQuery';
	var pSuggestTypeClass 		= 'suggestTextType';
	var pSuggestAmountClass     = 'suggestTextAmount';
	var pSuggestQueryTypedClass = 'suggestTextQueryTyped';
	var pSuggestFooterClass     = 'suggestFooter';
	var pSuggestHeaderClass     = 'suggestHeader';
	var pSuggestRowClass	    = 'suggestRow';
	var pSuggestHighlightClass  = 'suggestHighlight';

	var ptranslation;
	var language;

	this.init = function(searchURL, formname, queryParamName, divLayername, instanceName, debugMode, channelParamName, channel, showImages, setLanguage) {
	    if (typeof(setLanguage)=='undefined') setLanguage='DE';
	    language=setLanguage.toUpperCase();
		pSearchURL			= searchURL;
		pFormname			= formname;
		pQueryParamName		= queryParamName;
		pChannelParamName	= channelParamName;
		pChannel			= channel;
		pLayerName			= divLayername;
		pInstanceName		= instanceName;
 		pDebug				= debugMode;
 		pShowImages			= showImages;
		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).keyup(function(ev){handleKeyPress(ev);});
		$(pQueryInput).focus(function(){showLayer();});
		$(pQueryInput).blur(function(){hideLayer();});
		$(document[pFormname]).submit(function(){handleSubmit();});

		ptranslation = new Object();
		if (language=='EN') {
			ptranslation['unspecified'] = 'Unspecified';
			ptranslation['articleId'] = 'Nr.';
			ptranslation['deeplink'] = 'deeplink';
			ptranslation['productName'] = 'Product name';
			ptranslation['brand'] = 'Manufacturer';
			ptranslation['content'] = 'Content';
			ptranslation['searchTerm'] = 'Search term';
			ptranslation['category'] = 'Category';
		}
		if (language=='DE') {
			ptranslation['unspecified'] = 'Sonstiges';
			ptranslation['articleId'] = 'Nr.';
			ptranslation['deeplink'] = 'deeplink';
			ptranslation['productName'] = 'Produktname';
			ptranslation['brand'] = 'Hersteller';
			ptranslation['content'] = 'Inhalt';
			ptranslation['searchTerm'] = 'Suchbegriff';
			ptranslation['category'] = 'Kategorie';
		}
		if (language=='DK') {
			ptranslation['unspecified'] = 'Andre';
			ptranslation['articleId'] = 'Nr.';
			ptranslation['deeplink'] = 'deeplink';
			ptranslation['productName'] = 'Produktnavn';
			ptranslation['brand'] = 'Producent';
			ptranslation['content'] = 'Indhold';
			ptranslation['searchTerm'] = 'S&oslash;geord';
			ptranslation['category'] = 'Kategori';
		}
	}

	function handleSubmit() {
		var id = $('tr.'+pSuggestHighlightClass).attr("id");
		if (id != undefined) {
			var id = $('tr.'+pSuggestHighlightClass).attr("id");
			var query;
			for (var i=0; i<pSuggest.length; i++) {
				if (pSuggest[i].search(id)==0) {
					query = pSuggest[i].substring(id.length);
					window.location.href=pDeeplink[i]; // Link öffnen, anstatt Suchfeld zu füllen...
					return;
					break;
				}
			}
			addInputToForm('userInput', document[pFormname][pQueryParamName].value);
			document[pFormname][pQueryParamName].value = query;
			addInputToForm('queryFromSuggest', 'true');
		}
		window.location.href='ffsearch.php?query='+escape(document[pFormname][pQueryParamName].value);
	}

	this.handleClick = function() {
		$(document[pFormname]).submit();
	}

	this.handleMouseOver = function(id) {
		unmarkAll();
		$('#'+pLayerName+' tr[id="'+id+'"]').removeClass(pSuggestRowClass).addClass(pSuggestHighlightClass);
	}

	this.handleMouseOut = function(id) {
		$('#'+pLayerName+' tr[id="'+id+'"]').removeClass(pSuggestHighlightClass).addClass(pSuggestRowClass);
	}

	function handleKeyPress(evt) {
		evt = (evt) ? evt : ((event) ? event : null);
		var keyCode = evt.keyCode;
		if (keyCode == 38) {
			moveUp();
		} else if (keyCode == 27) {
			hideLayer();
		} else if (keyCode == 40) {
			moveDown();
		} else {
			if (pQueryInput.value == '') {
				hideLayer();
				pLastQuery = '';
				return null;
			}
			if (pLastQuery != pQueryInput.value){ getSuggestions(); }
			pLastQuery = pQueryInput.value;
		}
	}


	function moveUp(){
		if($('tr.'+pSuggestHighlightClass).length == 0){
		 	$('tr.'+pSuggestRowClass+':last').removeClass(pSuggestRowClass).addClass(pSuggestHighlightClass);
	 	}else{
		 	if($('tr.'+pSuggestHighlightClass).prev('tr.'+pSuggestRowClass).length == 0){
			 	$('tr.'+pSuggestHighlightClass).removeClass(pSuggestHighlightClass).addClass(pSuggestRowClass);
			 	$('tr.'+pSuggestRowClass+':last').removeClass(pSuggestRowClass).addClass(pSuggestHighlightClass);
			 }
			 else{
			 	$('tr.'+pSuggestHighlightClass)
			 	.removeClass(pSuggestHighlightClass).addClass(pSuggestRowClass)
		 		.prev('tr.'+pSuggestRowClass).removeClass(pSuggestRowClass).addClass(pSuggestHighlightClass);
		 	}
	 	}
	}

	function moveDown(){
		if($('tr.'+pSuggestHighlightClass).length == 0){
		 	$('tr.'+pSuggestRowClass+':first')
		 	.removeClass(pSuggestRowClass)
		 	.addClass(pSuggestHighlightClass);
	 	}
	 	else{
		 	if($('tr.'+pSuggestHighlightClass).next('tr.'+pSuggestRowClass).length == 0){
			 	$('tr.'+pSuggestHighlightClass).addClass(pSuggestRowClass).removeClass(pSuggestHighlightClass);
			 	$('tr.'+pSuggestRowClass+':first').removeClass(pSuggestRowClass).addClass(pSuggestHighlightClass);
		 	}
		 	else{
			 	$('tr.'+pSuggestHighlightClass).addClass(pSuggestRowClass).removeClass(pSuggestHighlightClass)
		 		.next('tr.'+pSuggestRowClass).removeClass(pSuggestRowClass).addClass(pSuggestHighlightClass);
		 	}
	 	}
	}

	function getSuggestions(){
		var query = $('input[name='+pQueryParamName+']').attr('value');
		//check if the same query was asked before
		if(pLastQuery == query){
			return;
		}
		else {
			pLastQuery = query;
		}
			var requestURL = pSearchURL +'?'+ pQueryParamName +'='+ encodeURIComponent(query) +'&'+ pChannelParamName +'='+ pChannel+'&format=json';
		$.ajax({
			type: "GET",
			url: requestURL,
			contentType: "application/x-www-form-urlencoded; charset=UTF-8",
			success:
				function (json, textStatus) {
					var jsonObj = eval(json);
					if (jsonObj.length > 0) {
						//create output text
						var clickAction='onMouseDown="' + pInstanceName + '.handleClick();"';
						var outputText = '<table cellpadding="0" cellspacing="0" class="' + pLayerName + '" width="100%" border="0" >';
						outputText += '<tr class="'+pSuggestHeaderClass+'" ><td nowrap="nowrap" colspan="'+(1+pShowImages)+'">';
						if (language=='EN'){
							outputText += 'Suggestions for your search...';
						}
						if (language=='DK'){
							outputText += 'Forslag til din s&oslash;gning...';
						}
						if (language=='DE'){
							outputText += 'Vorschl&auml;ge zu Ihrer Suche...';
						}

						outputText += '</td></tr>';

						pSuggest = new Array();
						pDeeplink = new Array();
						for (var i=0; i<jsonObj.length; i++) {
							var suggestQuery = jsonObj[i].query;
							var suggestCount = jsonObj[i].hitCount;
							if (suggestCount==0) {
								suggestCount = '';
							}else if (suggestCount==1) {
								suggestCount = 'Ein Produkt';
							}else {
								suggestCount = suggestCount + ' Produkte';
							}
							var _suggestType = jsonObj[i].type;
							var suggestType = ptranslation[jsonObj[i].type];
							if (!suggestType) {
								suggestType = "";
							}
							var suggestImageUrl = jsonObj[i].imageURL;
							var suggestArticleId = jsonObj[i].articleId;
							var suggestDeeplink = jsonObj[i].deeplink;
							var id = '_'+i+'_';
							var pDescription='';
							if (_suggestType=='searchTerm') {
								suggestDeeplink='ffsearch.php?query='+escape(jsonObj[i].query);
						  		pDescription='<span style="color:#666;">'+suggestType+':</span><br>' + suggestQuery.replace(new RegExp("("+query+")","ig"),'<span class="'+pSuggestQueryTypedClass+'">$1</span>');
								clickAction='onmousedown="window.location.href=\''+suggestDeeplink+'\'";return(false)';
							}
							if (_suggestType=='productName') {
							  clickAction='onmousedown="window.location.href=\''+suggestDeeplink+'\'";return(false)';
							  pDescription='<span style="color:#666;">' + suggestArticleId + '</span><br>' + suggestQuery.replace(new RegExp("("+query+")","ig"),'<span class="'+pSuggestQueryTypedClass+'">$1</span>');
							}
							if (_suggestType=='unspecified') {
								suggestDeeplink='ffsearch.php?query='+escape(jsonObj[i].query);
						  		pDescription='<span style="color:#666;">'+suggestType+':</span><br>' + suggestQuery.replace(new RegExp("("+query+")","ig"),'<span class="'+pSuggestQueryTypedClass+'">$1</span>');
								clickAction='onmousedown="window.location.href=\''+suggestDeeplink+'\'";return(false)';
							}
							if (_suggestType=='category') { // Kategorienummer wird beim Export vor den Namen gestellt und mit § Symbol zerstückelt (um falsche Suchtreffer zu vermeiden) z.B. "§1§0§3 Test" wäre Kategorie 103 mit Namen "Test"
								var p=suggestQuery.indexOf(' ');
								if (p) {
									suggestDeeplink='./c'+(suggestQuery.substring(0,p)).replace(/§/g,'')+'/';
									suggestQuery=suggestQuery.substring(p+1);
									clickAction='onmousedown="window.location.href=\''+suggestDeeplink+'\'"';
								}
								clickAction='onmousedown="window.location.href=\''+suggestDeeplink+'\'"';
								pDescription='<span style="color:#666;">'+suggestType+'</span><br>' + suggestQuery.replace(new RegExp("("+query+")","ig"),'<span class="'+pSuggestQueryTypedClass+'">$1</span>')
							}
							if (pDescription=='') {
							  clickAction='onmousedown="window.location.href=\''+suggestType+'\'";return(false)';
							  pDescription='<span style="color:#666;">'+suggestType+':</span><br>' + suggestQuery.replace(new RegExp("("+query+")","ig"),'<span class="'+pSuggestQueryTypedClass+'">$1</span>');
							}
							outputText += '<tr '+clickAction+' id="' + id + '" class="'+pSuggestRowClass+'" onMouseOver="' + pInstanceName + '.handleMouseOver(\'' + id + '\');" onMouseOut="' + pInstanceName + '.handleMouseOut(\'' + id + '\');">'
								+(pShowImages ? ('<td nowrap="nowrap" class="' + pSuggestImageClass + '"><img style="border:none" src="' + suggestImageUrl + '" alt=""/></td>') : '')
								+'<td nowrap="nowrap" class="'+ pSuggestQueryClass +'">' + pDescription + '</td>'
								+'</tr>';
							pSuggest[i] = id + suggestQuery;
							pDeeplink[i] = suggestDeeplink;
						}
						outputText += '<tr><td class="'+pSuggestFooterClass+'" colspan="'+(3+pShowImages)+'">&nbsp;</td></tr></table>';

						//show layer
						$('div#'+pLayerName).html(outputText).show();
					}
					else {
						//hide layer
						$('div#'+pLayerName).hide();
					}
				},
			error:
				function (e, xhr, settings, exception) {
					if (pDebug) {
						alert('Error:\nHTTP result code: ' + e.status+'\nrequested URL: '+requestURL);
					}
				}
		});
	}

	function hideLayer() {
		unmarkAll();
		$('div#'+pLayerName).hide();
		fireSuggestLayerHidden();
	}

	this.hideLayerOutsideCall = function() {
		hideLayer();
	}

	function showLayer() {
		$('div#'+pLayerName).show();
	}

	// calls the callback for "outside" listeners if the callback is implemented
	function fireSuggestCompleted(suggestLayerIsVisible) {
		if (typeof(onSuggestCompleted) == 'function') {
			onSuggestCompleted(suggestLayerIsVisible);
		}
	}

	// calls the callback for "outside" listeners if the callback is implemented
	function fireSuggestLayerHidden() {
		if (typeof(onSuggestLayerHidden) == 'function') {
			onSuggestLayerHidden();
		}
	}

	function unmarkAll() {
		$('tr.'+pSuggestHighlightClass).each(function(i) {
			$(this).removeClass(pSuggestHighlightClass).addClass(pSuggestRowClass);
		});
	}

	function addInputToForm(name, value) {
		var element = document.createElement('input');
		element.name = name;
		element.type = 'hidden';
		element.value = value;
		document[pFormname].appendChild(element);
	}
}
