
function TypeAhead(listName /*[,userName]*/ ) {
	
	this.typeAheadServiceURL = "http://localhost/acquireowebapp/QueryTerms.aspx";

	this.listName = listName			// Identifier for the suggestion list. Doesn't have to match the input field id or name attributes.	
	this.userName = "";					// group/user identifier (for private suggestions lists)
	if(arguments.length>1) 
		this.userName = arguments[1];

	this.inputId = null;				// id of the currently targeted text input
	this.inputElement = null; 			// reference to the currently targeted text input 

	this.suggestions = new Array();		// list of suggestions retrieved for the given input id
	this.matchingSuggestions = new Array();	// list of suggestions matching the user input
	this.suggestedText = "";			// latest suggested text
	this.userText = "";					// latest user typed text
	
	this.suggestionDropDown = null; 	// reference to the Drop Down DIV w/ the list of suggestions
	this.maxItemInDropDown = 20;		// max number of suggestions in the drop-down list
	var suggestedIndex = 0;				// index of the selected suggestion in the Drop Down list (changed w/ up & down arrows)
	var pressedKeyCount=0;
	
	var self = this;					// TypeAhead object reference
	var HTTPReq; 						// HTTP Request object reference
	var HTTPReqPost;					// HTTP Request object reference (used for POST Requests)

	var isWaitingForSuggestions = false; // Flag to show updated suggestion list
	var isThereMoreOnServer = false;	 // Flag to prevent useless server access

	// Debug Output
	var debugOutput = document.getElementById('debugOutput'); 
	function debug(text) { 
		//if(typeof debugOutput != "undefined" && debugOutput) 
		//	debugOutput.innerHTML = debugOutput.innerHTML+"<br /><hr />"+text; 
	}
	
	// INITIALIZATION ROUTINES ------------------------------------------------------------------------------------------------

	// init: runs when the object is instanciated.
	this.init = function()
	{
		if( window.ActiveXObject )
			HTTPReq = new ActiveXObject( "Microsoft.XMLHTTP" );
		else
			HTTPReq = new XMLHttpRequest();
			
//		debug( "URL: " + this.typeAheadServiceURL );
	}
	
	// initInput: to be run when the 'inputId' field is displayed or get the focus.
	this.initInput = function() { /*[inputId]*/

		// Make sure we have a valid id and a valid reference to the text input
		if(arguments.length>0) self.inputId = arguments[0];		
		if(self.inputId) self.inputElement = document.getElementById(self.inputId);
		if(self.inputElement && !self.inputId) {	
			if(!self.inputElement.id) self.inputElement.id = randomId();
			self.inputId = self.inputElement.id;
		}
		if(!self.inputId) return false;		
		self.userText = self.inputElement.value;

//		debug("TypeAhead Field Initialization: "+ self.inputId);

		// Create markup for drop-down list of suggestions
		self.suggestionDropDown = document.getElementById("THDropDown-" + self.inputId);
		if(!self.suggestionDropDown)
		{
			self.suggestionDropDown = document.createElement('DIV');
			self.suggestionDropDown.id = "THDropDown-" + self.inputId;
			self.suggestionDropDown.className = "THHideDropDown";
			self.suggestionDropDown = self.inputElement.parentNode.insertBefore(self.suggestionDropDown, self.inputElement.nextSibling);
			
			self.suggestionDropDown.style.top =   getTop( self.inputElement ) + self.inputElement.offsetHeight;
			self.suggestionDropDown.style.left =  getLeft( self.inputElement );
			self.suggestionDropDown.style.width = (self.inputElement.offsetWidth - 10).toString() + "px";
		}
		
		// Handle user input
		self.inputElement.onkeyup = function (evt)
		{
			if(!evt) evt = window.event;
			
			switch(evt.keyCode)
			{
				case 40:	// arrow down
					if( ++suggestedIndex > self.matchingSuggestions.length )
					    suggestedIndex = 0;
					
					self.suggest();
					break;
					
				case 38:	// arrow up
					if ( --suggestedIndex < 0 )
					    suggestedIndex = self.matchingSuggestions.length - 1;
					    
					self.suggest();
					break;
					
				default:
					pressedKeyCount--;
					if ( self.userText != self.inputElement.value)
					{
						suggestedIndex = 0;
						self.suggest(self.inputElement.value.toLowerCase());								
					}							
			}
		}
		
		self.inputElement.onkeydown = function(evt)
		{
			if(!evt) evt = window.event;
			
			if(evt.keyCode != 38 && evt.keyCode != 40 && evt.keyCode != 46 && evt.keyCode != 8)
			{
				pressedKeyCount++;
			}
		}
		
		self.inputElement.onfocus = function(evt)
		{
			self.updateSuggestionList();
			self.showSuggestionList();
		}
		
		// hides the suggestion drop-down when input field not in focus
		self.inputElement.onblur = function(evt)
		{
			window.setTimeout(function() {
							   self.suggestionDropDown.className = self.suggestionDropDown.className.replace("THShowDropDown","THHideDropDown");
							   },500);
		}
	}

	// SUGGESTION LIST IN/OUT ------------------------------------------------------------------------------------------------
	this.getSuggestions = function(text)
	{
		if (text) 
		{
		    self.userText = text;
		}

   		HTTPReq.abort();
		HTTPReq.onreadystatechange = self.populateSuggestionsFromService;	
		HTTPReq.open("GET", self.typeAheadServiceURL + "?inputid="+encodeURIComponent(self.listName)+"&inputtxt="+encodeURIComponent(self.userText)+"&user="+encodeURIComponent(self.userName), true);
		HTTPReq.send(null);
		
		// debug("request sent: "+"inputid="+encodeURIComponent(self.listName)+"&inputtxt="+encodeURIComponent(self.userText));
	}
	
	this.populateSuggestionsFromService = function(evt)
	{
	    if (HTTPReq.readyState == 4)
	    {			
		   	self.suggestions = HTTPReq.responseText.split("&");
			debug("response: "+ HTTPReq.responseText);			

			isThereMoreOnServer = self.suggestions.length >= 20;
			isWaitingForSuggestions = false;
			self.updateSuggestionList();
		    self.showSuggestionList();
	    }
	}

	// USER INPUT OPERATIONS  ------------------------------------------------------------------------------------------------

	// suggest: replace input value with suggested text.
	this.suggest = function(text)
	{
		if(text) self.userText = text;
		
		self.suggestedText = "";
		
		// can't suggest if more than one key is pressed at the same time
		if( suggestedIndex == 0 && pressedKeyCount == 0 )
		{   
			self.updateSuggestionList();
			if( self.matchingSuggestions.length > 0 )
			{
				self.suggestedText = self.matchingSuggestions[0];
				var startIndex = self.inputElement.value.length; 
				self.inputElement.value = self.suggestedText; 
				self.selectText(startIndex,  self.suggestedText.length );
		        self.showSuggestionList();
				return;
			}
		}
		
		if ( suggestedIndex > 0 )
		{
			// used up/down arrow key to select in the drop-down list			
			if ( self.matchingSuggestions.length > 0 )
			{
				self.suggestedText = self.matchingSuggestions[suggestedIndex-1];			
				var startIndex = self.inputElement.value.length; 
				self.inputElement.value = self.suggestedText; 
				self.selectText(startIndex,  self.suggestedText.length);
		        self.showSuggestionList();
				return;
			}
		}
		
	    self.getSuggestions();
        //self.showSuggestionList();
	}
	
	this.updateSuggestionList = function()
	{
		suggestedIndex = 0;
		var newSuggestionArray = new Array();
		var suglen = self.suggestions.length;
		if ( suglen > 0 )
		{
		    maxIdx = suglen > self.maxItemInDropDown ? self.maxItemInDropDown : 
		                                    suglen;
		}
		else
		{
		    maxIdx = 0;
		}
		                                    
		for (var i=0; i < maxIdx; i++)
		{ 
			if (self.suggestions[i].toLowerCase().indexOf(self.userText.toLowerCase()) == 0)
			{
				newSuggestionArray[newSuggestionArray.length] = self.suggestions[i];
			} 
		}		
		self.matchingSuggestions = newSuggestionArray;
	}
	
	this.showSuggestionList = function()
	{
		var htmlList="";
		
/*		var isb =  self.inputElement.style.bottom;
		var isl = self.inputElement.style.left;
		self.suggestionDropDown.style.top =   self.inputElement.style.bottom;
		self.suggestionDropDown.style.left =  self.inputElement.style.left; */
		for (var i=0; i < self.matchingSuggestions.length; i++)
		{ 
			if (self.matchingSuggestions[i].toLowerCase().indexOf(self.userText.toLowerCase()) == 0) {
				if(suggestedIndex-1 == i) 
					htmlList += "<li class='THLIHover' onclick='document.getElementById(\""+ self.inputId + "\").value=unescape(\""+ escape(self.matchingSuggestions[i]) +"\")' onmouseover='this.className+=\" THLIHover\"' onmouseout='this.className=this.className.replace(\"THLIHover\",\"\")' >"+self.matchingSuggestions[i]+"</li>";
				else
					htmlList += "<li onclick='document.getElementById(\""+ self.inputId + "\").value=unescape(\""+ escape(self.matchingSuggestions[i]) +"\")' onmouseover='this.className+=\" THLIHover\"' onmouseout='this.className=this.className.replace(\"THLIHover\",\"\")' >"+self.matchingSuggestions[i]+"</li>";
            } 			
        }
        
		if( htmlList == "" )
		{
		    // Do not show the list if it is empty.
		    self.suggestionDropDown.className = self.suggestionDropDown.className.replace("THShowDropDown","THHideDropDown");
	    }
		else
		{
			self.suggestionDropDown.innerHTML = "<ul>"+htmlList+"</ul>";
		    self.suggestionDropDown.className = self.suggestionDropDown.className.replace("THHideDropDown","THShowDropDown");
		}
	}


	// UTILITY FUNCTIONS  ------------------------------------------------------------------------------------------------
	this.selectText = function(startIndex, nbChars)
	{
		if (self.inputElement.createTextRange) { // for Internet Explorer
			var txtRange = self.inputElement.createTextRange(); 
			txtRange.moveStart("character", startIndex); 
			txtRange.moveEnd("character", nbChars - self.inputElement.value.length);      
			txtRange.select();           
    	}
		else if (self.inputElement.setSelectionRange) { // for Mozilla
        	self.inputElement.setSelectionRange(startIndex, nbChars);
	    }     
		//set focus back to the textbox
		self.inputElement.focus();    
	}

	function getTop(obj)
	{
		var cur = 0;
		if(obj.offsetParent) {		
			while(obj.offsetParent) {
				cur+=obj.offsetTop;
				obj = obj.offsetParent;
			}
		}
		return cur;
	}
	
	function getLeft(obj)
	{
		var cur = 0;
		if(obj.offsetParent)
		{		
			while(obj.offsetParent) {
				cur+=obj.offsetLeft;
				obj = obj.offsetParent;
			}
		}
		return cur;
	}
	
	function randomId() {
		var rId = "";
		for (var i=0; i<6;i++)
			rId += String.fromCharCode(97 + Math.floor((Math.random()*24)))
		return rId;
	}
}


// Utility functions
var XBrowserAddHandler = function (target,eventName,handlerName)
{
	if(!target) return;
	if (target.addEventListener) { 
		target.addEventListener(eventName, function(e){eval(handlerName)(e);}, false);
	} else if (target.attachEvent) { 
		target.attachEvent("on" + eventName, function(e){eval(handlerName)(e);});
		} else { 
		// THIS CODE NOT TESTED 
		var originalHandler = target["on" + eventName]; 
		if (originalHandler) { 
		  target["on" + eventName] = function(e){originalHandler(e);eval(handlerName)(e);}; 
		} else { 
		  target["on" + eventName] = eval(handlerName); 
		} 
	} 
}


