/*  
	Title : Auto Suggest Box
	Author : Tom Coote
	Wedsite : http://www.tomcoote.co.uk
*/

 /**
	* @argument SearchInputID - The id of the text input for the loop up.
	* @argument MultiSelectID - The id of the select tag for the results to be placed.
	* @argument fnSearch - The JavaScript function to call to get results, 
	*						this function will get passed a string value of the requested search text and
	*						must return an array of objects with the following members; id, text
	* @argument fnFound - The JavaScript function to call when a result is selected,
	*						this function will get passed the id and text of the selected object plus any extra arguments passed in
	*						when the results were created.
	*/
function AutoSuggestBox(SearchInputID, MultiSelectID, fnSearch, fnFound) {
    
	var that = {}; // Must use 'that' so not to confuse with 'this' which is the global object.

	/* Private Variables 
	*
	* These variables can only be accessed by functions inside the scope of this object.
	*/
	var eSearchInput, eMultiSelect;
	var iMaxListHeight = 280;
	var arrArgs; 
	var iSelectTextHeight = 22; // You may need to change this depending on your CSS.
	var selectedIndex = -1;
	var ignoreMouseOver = false;

	var ie = (document.all) ? true : false;
    /* Private Functions 
	*
	* These functions can only be accessed by functions inside the scope of this object.
	*/

	function Initiate() {
		eSearchInput = document.getElementById(SearchInputID);
		eMultiSelect = document.getElementById(MultiSelectID);

		// Position the results area directly underneath the input box ready for deployment
		PositionElement();
		eMultiSelect.style.visibility = 'hidden';

		eSearchInput.ondblclick = function (){
			that.showResults("");
		};
	}

	function GetResultClickHandler() {
		if (selectedIndex == -1)
			return;
		document.onclick = "";
		document.onkeydown = "";
		document.onkeypress = "";

		var lis = eMultiSelect.getElementsByTagName("li");

		var l = lis[selectedIndex];
		var temp = l.getElementsByTagName("span");

		var text = temp[0].innerHTML;
		var temp = l.getElementsByTagName("input");
		var id = temp[0].value;

		eSearchInput.value = text;
		eMultiSelect.style.visibility = 'hidden';
		fnFound(id,text,arrArgs);
	}
/*	function GetResultKeyPressHandler(e) {
		if (GetKeyCode(e) == 13) 
			GetResultClickHandler();
	}
*/
	function GetKeyCode(e)
	{
		if (e) {
			return e.charCode ? e.charCode : e.keyCode;
		}
		else {
			return window.event.charCode ? window.event.charCode : window.event.keyCode;
		}
	}

	function PositionElement() {
		eMultiSelect.style.position = 'absolute';
		eMultiSelect.style.width = eSearchInput.offsetWidth + 'px';
	}

	/* Public Variables 
	*
	* These variables are available from the returning object that this constructor creates,
	* new public variables can be added to the returning object at any time.
	*/
	var undefined;

	/* Public Functions 
	*
	* These functions are available from the returning object that this constructor creates,
	* new public functions can be added to the returning object at any time.
	*/
	that.KeyPressHandler = function(e){
		var unicode = GetKeyCode(e);

		var lis = eMultiSelect.getElementsByTagName('li');
		//tab pressed
		if (unicode == 9){
			eMultiSelect.style.visibility = 'hidden';
			document.onclick = "";
			document.onkeydown = "";
			document.onkeypress = "";
			return false;
		}

		if (unicode == 13 && eMultiSelect.style.visibility == 'visible'){
			if (selectedIndex != -1){
				GetResultClickHandler();
				return false;
			}
		}
		// Check for up/down key press
		if (unicode == 40) {
			if (selectedIndex == -1)
				that.changeSelected(0, true);
			else 
				that.changeSelected(selectedIndex + 1, true);
			return;
		}
		if (unicode == 38) {
			if (selectedIndex == -1)
				that.changeSelected(0, true);
			else 
				that.changeSelected(selectedIndex - 1, true);
			return;
		}
	}
			

	that.CreateResults = function(e) {
		// Check for additional arguments
		if (arguments != undefined) {
			arrArgs = arguments;
		}
		
		var unicode = GetKeyCode(e);
		if (unicode == 13 && eMultiSelect.style.visibility == 'visible'){
			var lis = eMultiSelect.getElementsByTagName("li");
			if (lis.length == 1){
				selectedIndex = 0;
				GetResultClickHandler();
				return false;
			}
		}

		if ((unicode == 40 || unicode == 38) && eMultiSelect.style.visibility == "visible")
			return;

		that.showResults(eSearchInput.value);
	}

	that.changeSelected = function(newIndex, controlScroll){
		var lis = eMultiSelect.getElementsByTagName("li");
 		if (newIndex >= lis.length || newIndex < 0)
			return;
		for (i=0;i<lis.length;i++)
			lis[i].id = "";
		lis[newIndex].id = "marked";
		if (controlScroll){
			if (lis[newIndex].offsetTop > eMultiSelect.offsetHeight/2){
				that.ignoreMouseOver = true;
				eMultiSelect.scrollTop = lis[newIndex].offsetTop - eMultiSelect.offsetHeight/2;
			}
			else {
				that.ignoreMouseOver = true;
				eMultiSelect.scrollTop = 0;
			}
		}
		selectedIndex = newIndex;
	}

	that.showResults = function(str){
		selectedIndex = -1;
		// Get results
		document.onclick = function(event){
			if (!event)					//ie 
				event = window.event;
			var srcElement = event.srcElement;
			if (!srcElement)
				srcElement = event.target;
			if (srcElement != eMultiSelect && srcElement != eSearchInput){
				document.onclick = "";
				document.onkeydown = "";
				document.onkeypress = "";
				eMultiSelect.style.visibility = 'hidden';
			}
		}
		if (!ie || (navigator.userAgent && navigator.userAgent.indexOf("Opera") != -1))
			document.onkeypress = that.KeyPressHandler;
		else
			document.onkeydown = that.KeyPressHandler;

		var arrResults = fnSearch(str), i, eOption, iCount = 0;
		
		if (arrResults == undefined) {
			eMultiSelect.style.visibility = 'hidden';
			document.onclick = "";
			document.onkeydown = "";
			document.onkeypress = "";
			return;
		}

		eMultiSelect.innerHTML = ''; 

		for (i=0; i < arrResults.length; i++) {
			if (arrResults[i] != undefined) {

				eOption = document.createElement('li');
				var textElem = document.createElement('span');
				textElem.innerHTML = arrResults[i].text;
				
				var idElem = document.createElement('input');
				idElem.type = "hidden";
				idElem.value = arrResults[i].id;

				var posElem = document.createElement('input');
				posElem.type = "hidden";
				posElem.value = i;
				
				eOption.appendChild(textElem);
				eOption.appendChild(idElem);
				eOption.appendChild(posElem);

				eOption.onclick = function (){
					var inputs = this.getElementsByTagName("input");
					selectedIndex = inputs[1].value;
					GetResultClickHandler();
				}
				eOption.onmouseover = function (){
					if (that.ignoreMouseOver){
						that.ignoreMouseOver = false;
						return;
					}
					
					var lis = eMultiSelect.getElementsByTagName("li");
					for (k=0;k<lis.length;k++){
						if (lis[k] == this){
							that.changeSelected(k, false);
							break;
						}
					}
				};
				

				eMultiSelect.appendChild(eOption);

				iCount++;
			}
		}

		if (iCount < 1) {
			eMultiSelect.style.visibility = 'hidden';
			document.onclick = "";
			document.onkeydown = "";
			document.onkeypress = "";
			return; // No results found.
		}

		PositionElement();
		var iHeight = iCount*iSelectTextHeight; 
	
		if (iCount > 2) {
			if (iHeight > iMaxListHeight) { // Don't want it to tall on the page
				eMultiSelect.style.height = iMaxListHeight+'px';
			}
			else {
				eMultiSelect.style.height = iHeight+'px';
			}
		}

		eMultiSelect.style.visibility = 'visible';
	}

	Initiate(); // Do all setup when the object is created.

	/* 
	* This (or that) is the object returned with all public members and
	* functions included above when the contructor is instantiated.
	*/
    return that;
}

