/* function that handles the keys that are pressed */
function suggestion (newField) {

	if (newField) {
		/* flag that indicates if the up or down arrow keys were pressed
		the last time a keyup event occurred  */
		var isKeyUpDownPressed = false;
		/* the currently selected suggestion (by arrow keys or mouse)*/
		var position = -1;
		/* number of suggestions received as results for the keyword */
		var numResults = 0;
		/* the minimum and maximum position of the visible suggestions */
		var minVisiblePosition = 0;
		var maxVisiblePosition = 10;
		/* the maximum number of characters to be displayed for a suggestion */
		var suggestionMaxLength = 30;
		/* default text in input field */
		var defaultText = '';
		/* the last keyword for which suggests have been requested */
		var userKeyword = '';
		/* the last suggestion that has been used for autocompleting the keyword */
		var autocompletedKeyword = '';
		/* cache object containing the retrieved suggestions for different keywords */
		var suggestionCache = new Object();
		/* flag that indicates if there are results for the current requested keyword*/
		var hasResults = false;
		/* remember the field name */
		var field = newField;
		/* path to list */
		var list = document.getElementById(field+'-suggestion').getElementsByTagName('ul')[0];
		/* path to input field */
		var inputField = document.getElementById(field + '-input');
		/* path to form */
		var form = document.forms['searchForm'];
		/* inputed keyword */
		var inputKeyword = new String();

		/* handle events */
		inputField.onkeyup = function (event){
			handleKeyUp(event);
		};
		inputField.onfocus = function(){
			if (this.value == defaultText) this.value = '';
		};
		inputField.onblur = function(){
			if (this.value == '') this.value = defaultText;
		};
		inputField.onclick = function(){
			hideSuggestions();
		};

		inputField.setAttribute("autocomplete", "off");
	}

	/* methods */
	this.setDefaultText = function(txt){
		inputField.value = txt;
		defaultText = txt;
		}

	/* get response from ajax request */
	this.getResponse = function (response){
		var newCache = new Array();
		// check to see if we have any results for the searched keyword
		if(response.childNodes.length) {
			newCache = xmlToArray(response.getElementsByTagName("name"));
		}
		addSuggestionCache (userKeyword, newCache);
	}



	function handleKeyUp (e) {

		// get the event
		e = (!e) ? window.event : e;
		// get the event's target
		target = (!e.target) ? e.srcElement : e.target;
		if (target.nodeType == 3)
			target = target.parentNode;
		// get the character code of the pressed button
		code = (e.charCode)
			? e.charCode
			: ((e.keyCode)
				? e.keyCode
				: ((e.which) ? e.which : 0)
			);

		// check to see if the event was keyup
		if (e.type == "keyup") {
			isKeyUpDownPressed =false;
			switch (code) {
				/* if Enter is pressed we jump to the PHP help page of the current
					function */
				case 13: {
					// check to see if any suggestion is currently selected
					if(position>=0) {
						e.returnValue = false;
						e.cancel = true;
						e.cancelBubble = true;
						submitSearch();
					}
					break;
				}

				/* if Esc is pressed */
				case 27: {
					// check to see if any suggestion is currently selected
					hideSuggestions();
					break;
				}

				// if the up arrow is pressed we go to the previous suggestion
				case 38: {
					if(position <= (numResults - 1)) {
						position--;
						// deselect the old selected suggestion
						oldLn = list.getElementsByTagName('li')[position+1];
						oldLn.className = "";
						if (position >=0) {
							// select the new suggestion and update the keyword
							newLn = list.getElementsByTagName('li')[position];
							newLn.className = "highlight";
						}
						updateKeywordValue(newLn);
					}

					// scroll down if the current window is no longer valid
					if(position < minVisiblePosition) {
						list.scrollTop -= 14;
						maxVisiblePosition -= 1;
						minVisiblePosition -= 1;
					}

					e.cancelBubble = true;
					e.returnValue = false;
					isKeyUpDownPressed = true;

					break;
				}

				// if the down arrow is pressed we go to the next suggestion
				case 40: {
					if(position < (numResults - 1)) {
						position++;
						// select the new suggestion and update the keyword
						newLn = list.getElementsByTagName('li')[position];
						newLn.className = "highlight";
						// deselect the old selected suggestion
						if (position >0) {
							oldLn = list.getElementsByTagName('li')[position-1];
							oldLn.className = "";
						}
						updateKeywordValue(newLn);
					}

					// scroll down if the current window is no longer valid
					if(position > maxVisiblePosition) {
						list.scrollTop += 14;
						maxVisiblePosition += 1;
						minVisiblePosition += 1;
					}

					e.cancelBubble = true;
					e.returnValue = false;
					isKeyUpDownPressed = true;

					break;
				}

				default: {
					checkForChanges();
					e.returnValue = false;
					e.cancelBubble = true;
				}
			}
		}
	}





	/* function that checks to see if the typed keyword has changed */
	function checkForChanges() {

		// retrieve the keyword object
		inputKeyword = inputField.value;

		// check to see if the keyword is empty
		if (inputKeyword == '') {
			// hide the suggestions
			hideSuggestions();
			// reset the keywords
			userKeyword = '';
		}
		// check if keyword isn't null and there are any changes and the last pressed key wasn't up or down
		if ( (inputKeyword != '')
			&& (userKeyword != inputKeyword)
			&& (autocompletedKeyword != inputKeyword)
			&& (isKeyUpDownPressed == false)
		) {
			// update the suggestions
			getSuggestions(inputKeyword);
		}
	}

	/* function that hides the layer containing the suggestions */
	function hideSuggestions() {
		list.style.display = 'none';
		resetList();
	}

	/* initiate HTTP request to retrieve suggestions for the current keyword */
	function getSuggestions (keyword) {

		// check to see if the keyword is in the cache
		if (checkSuggestionCache(inputKeyword) == true) {
			// retrieve the results from the cache
			userKeyword = keyword;
			// display the results from the cache
			outputSuggesions();
		}
		// if the keyword isn't in cache, make an HTTP request
		else if (userKeyword != keyword) {
			userKeyword = keyword;
			sendRequest("action=suggestion&keyword=" + encodeURIComponent(keyword), field);
			// wait for response
			setTimeout(function (){getSuggestions(keyword)},100);
		}
		else setTimeout(function (){getSuggestions(keyword)},100);
	}

	/*
	function that checks to see if the keyword specified as parameter is in
	the cache or tries to find the longest matching prefixes in the cache
	and adds them in the cache for the current keyword parameter
	*/
	function checkSuggestionCache (keyword) {
		// check to see if the keyword is already in the cache
		if (suggestionCache[keyword]) {
			return true;
		}
		// try to find the biggest prefixes
		for (i=keyword.length; i>=0; i--) {
			// compute the current prefix keyword
			var currentKeyword = keyword.substring(0, i);
			// check to see if we have the current prefix keyword in the cache
			if (suggestionCache[currentKeyword]) {
				// the current keyword's results already in the cache
				var cacheResults = suggestionCache[currentKeyword];
				// the results matching the keyword in the current cache results
				var keywordResults = new Array();
				var keywordResultsSize = 0;
				// try to find all matching results starting with the current prefix
				for(j=0; j<cacheResults.length; j++) {
					if(cacheResults[j].indexOf(keyword) == 0)
						keywordResults[keywordResultsSize++] = cacheResults[j];
					else if (cacheResults[j].indexOf(' '+keyword) > 0)
						keywordResults[keywordResultsSize++] = cacheResults[j];
				}
				// add all the keyword's prefix results to the cache
				addSuggestionCache (keyword, keywordResults);
				return true;
			}
		}
		// no match found
		return false;
	}

	/* function that adds to a keyword an array of values */
	function addSuggestionCache (keyword, values) {
		// create a new array entry in the cache
		suggestionCache[keyword] = new Array();
		// add all the values to the keyword's entry in the cache
		for(i=0; i<values.length; i++) {
			suggestionCache[keyword][i] = values[i];
		}
	}

	/* populates the list with the current suggestions */
	function outputSuggesions () {

		// get the number of results from the cache
		numResults = suggestionCache[userKeyword].length;
		resetList();

		if (numResults > 0) {
			// resets the flag indicating whether the up or down key has been pressed
			isKeyUpDownPressed = false;
			/* sets the flag indicating that there are results for the searched for keyword */
			hasResults = true;
			// loop through all the results and generate the HTML list of results


			for (var i=0; i < numResults; i++) {
				// retrieve the current function
				var currentSuggestion = suggestionCache[userKeyword][i];
				currentSuggestion = currentSuggestion.replace(userKeyword, '<b>' + userKeyword + '</b>');
				var li = document.createElement("li");
				li.id = 'suggestion-' + i;
				li.i = i;
				li.onmouseover = function (){ handleOnMouseOver(this)};
				li.onmouseout = function (){ handleOnMouseOut(this)};
				li.onclick= function (){ submitSearch(this)};
				li.innerHTML = currentSuggestion;
				list.appendChild(li);
			}
		// if the array of results is empty display a message
		} else {
			// set the flag indicating that no results have been found
			// and reset the counter for results
			hasResults = false;

			// create new li tag
			var li = document.createElement("li");
			li.innerHTML = 'No results found for <strong>' + userKeyword + '</strong>';
			list.appendChild(li);
		}

		list.style.display = "block";

/*
		var oScroll = document.getElementById(suggesTo + '-scroll');
		// scroll to the top of the list
		oScroll.scrollTop = 0;
		// update the suggestions list and make it visible
*/
	}

	/* reset the UL list from li tags */
	function resetList() {
		// resets the index of the currently selected suggestion
		position = -1;
		// remove all suggestions
		while (list.childNodes[0]) {
			list.removeChild(list.childNodes[0]);
		}
	}

	/* function that handles the mouse entering over a suggestion's area
	event */
	function handleOnMouseOver(obj) {
		position = obj.i;
		selectSuggestion(obj);
		updateKeywordValue(obj);
	}

	/* function that handles the mouse exiting a suggestion's area event */
	function handleOnMouseOut(obj) {
		obj.className = "";
		position = -1;
	}

	/* function that removes the style from all suggestions and select the current selected */
	function selectSuggestion(obj) {
		var li = list.getElementsByTagName("li");
		var currentPosition = obj.i;
		for(var i=0; i<li.length; i++){
			li[i].className = (i==(currentPosition)) ? "highlight" : "";
		}
	}

	/* function that updates the keyword value with the value
	of the currently selected suggestion */
	function updateKeywordValue(obj) {
		var currentPosition = obj.i;
		inputField.value = suggestionCache[userKeyword][currentPosition];
		//  selectRange(oKeyword, httpRequestKeyword.length, oKeyword.value.length);
	}

	function submitSearch() {
		form.submit();
		//document.location.href = "?action=search&keyword=" + encodeURIComponent(inputField.value);
	}

}
