//Common script functions for AutoComplete controls

function AutoCompleteItem(id,path,name,data,level)
{
	this.id = id;
	this.path = path;
	this.name = name;
	this.data = data;
	this.level = level;
}

function AutoComplete(prefix,targetID,minInputLength,maxResults,servicePath,serviceMethod,serviceContext,onChangeHandler,formatHandler,valueSeparator,suggestions)
{
	var TAB = 9;
	var ENTER = 13;
	var ESC = 27;
	var PAGEUP = 33;
    var PAGEDOWN = 34;
    var END = 35;
    var HOME = 36;
    var LEFT = 37;
    var RIGHT = 39;
    var KEYUP = 38;
	var KEYDN = 40;

	var me = this;
	this.div = document.getElementById(prefix + "_AutoCompleteOptions");
	this.elem = document.getElementById(targetID);
	this.inputText = null;
	this.formatHandler = formatHandler;
	this.matches = new Array();
	this.matchesCache = null;
	this.maxResults = maxResults;
	this.minInputLength = minInputLength;
	this.onChangeHandler = onChangeHandler;
	this.prefix = prefix;
	this.selectedIndex = -1;
	this.serviceContext = serviceContext;
	this.serviceMethod = serviceMethod;
	this.servicePath = servicePath;
	this.suggestions = suggestions;
	this.timer = null;
	this.valueSeparator = valueSeparator;
	
	//turn off browser autocomplete
	this.elem.setAttribute("autocomplete","off");

	/********************************************************
	onkeydown event handler for the input elem.
	Tab key = use the selectedIndex suggestion, if there is one.
	Esc key = get rid of the autosuggest dropdown
	Up/down arrows = Move the highlight up and down in the suggestions.
	********************************************************/
	this.elem.onkeydown = function(ev)
	{
		var key = me.getKeyCode(ev);
		switch(key)
		{
			case TAB:
				me.select();
				break;
			case ENTER:
				me.select();
				me.cancelEvent(ev);
				break;
			case ESC:
				me.hide();
				break;
			case KEYUP:
				if (me.selectedIndex > 0)
					me.selectedIndex--;
				me.changeHighlight(key);
				break;
			case KEYDN:
				if (me.selectedIndex < (me.matches.length - 1))
					me.selectedIndex++;
				me.changeHighlight(key);
				break;
			case LEFT: case RIGHT: case PAGEUP: case PAGEDOWN: case END: case HOME:
				break;
			default:
				me.setSelection(0,me.elem.value);
				me.setPopulateTimeout();
		}
	};
	
	this.elem.onblur = function(ev)
	{
		me.setHideTimeout();
	};

	this.cacheMatches = function(text)
	{
		if (!this.matchesCache)
			this.matchesCache = new Array();
		this.matchesCache[text] = this.matches;
	};

	this.cancelEvent = function(ev)
	{
		if(ev) //Moz
		{
			ev.preventDefault();
			ev.stopPropagation();
		}
		if(window.event) //IE
			window.event.returnValue = false;
	}

	this.changeHighlight = function()
	{
		var lis = this.div.getElementsByTagName("li");
		for (i in lis)
		{
			var li = lis[i];
			if (li)
			{
				if (this.selectedIndex == i)
					li.className = "Selected";
				else
					li.className = "";
			}
		}
	};
	
	this.getEventSource = function(ev)
	{
		if(ev) //Moz
			return ev.target;
		if(window.event) //IE
			return window.event.srcElement;
	};
		
	this.getKeyCode = function(ev)
	{
		if(ev) //Moz
			return ev.keyCode;
		if(window.event) //IE
			return window.event.keyCode;
	};
	
	this.getMatches = function()
	{
		var text = this.inputText.toLowerCase();
		this.matches = new Array();
		if (text && text.length >= this.minInputLength)
		{
			if (this.matchesCache && this.matchesCache[text])
			{
				this.matches = this.matchesCache[text];
				this.formatMatches()
			}
			else
			{
				//call web service to get matches
				Sys.Net.WebServiceProxy.invoke(this.servicePath, this.serviceMethod, false, {context: this.serviceContext, searchTerm: text, maxRecords: this.maxResults}, Function.createDelegate(this, this.onServiceComplete), Function.createDelegate(this, this.onServiceFailed), text);
			
				/*for (i in this.suggestions) 
				{
					var suggestion = this.suggestions[i];
					if(suggestion.name.toLowerCase().indexOf(text) >= 0)
						this.matches[this.matches.length] = suggestion;
				}
				this.cacheMatches(text);*/
			}
		}
	};	

	this.hide = function()
	{
		this.div.style.display = "none";
		this.selectedIndex = -1;
		if (this.timer)
			window.clearTimeout(this.timer);
	};
	
	this.onServiceComplete = function(result, text, methodName)
	{
		this.parseMatches(result);
		this.cacheMatches(text);
		this.formatMatches();
	};
	
	this.onServiceFailed = function(err, response, context)
	{
	};
	
	this.parseMatches = function(items)
	{
		if (items)
		{
			for (var i=0; i<items.length; i++)
			{
				var values = items[i].split("|");
				var item = new AutoCompleteItem(values[0],values[1],values[2],values[3],values[4]);
				this.matches[this.matches.length] = item;
			}
		}
	};
	
	this.populate = function()
	{
		var sep = this.valueSeparator;
		var value = this.elem.value;
		
		if (!sep && !sep.length)
			this.inputText = value;
		else
		{	
			var index = value.lastIndexOf(sep);
			if (index == -1)
				this.inputText = value;
			else
				this.inputText = value.substring(index+1);
		}
		this.getMatches();
	};
	
	this.show = function()
	{
		this.div.style.display = "block";
	};
	
	this.reposition = function()
	{
		//this.elem.style.left = "0px";
		//this.elem.style.top = "0px";
		//item_reposition(this.elem,this.div);
	};
	
	this.select = function()
	{
		if (this.selectedIndex > -1)
		{
			var match = this.matches[this.selectedIndex];
			this.setSelection(match.id,match.name);
			this.hide();
		}
		this.elem.focus();
	};
	
	this.setHideTimeout = function()
	{
		if(this.timer)
			window.clearTimeout(this.timer);
		this.timer = window.setTimeout(Function.createDelegate(this,this.hide),200);
	}
	
	this.setPopulateTimeout = function()
	{
		if(this.timer)
			window.clearTimeout(this.timer);
		this.timer = window.setTimeout(Function.createDelegate(this,this.populate),350);
	};
	
	this.setSelection = function(id,name)
	{
		if (this.onChangeHandler && this.onChangeHandler.length)
			eval(this.onChangeHandler + "('" + this.prefix + "','" + id + "','" + escape(name) + "');");
		else
			this.elem.value = match.name;
	};

	/********************************************************
	Create AutoComplete options
	********************************************************/
	this.formatMatches = function()
	{
		var ul = document.createElement("ul");
		this.selectedIndex = -1;
	
		//determine if custom formatter was provided
		var customFormat = (this.formatHandler && this.formatHandler.length);
	
		//create <li><a> for each item
		for (i in this.matches)
		{
			var item = this.matches[i];
			var li;
			
			if (customFormat)
			{	
				//get li from custom format function
				li = eval(this.formatHandler + "(item);");
			}
			else
			{
				//create li
				li = document.createElement("li");
				li.setAttribute("matchindex",i);
				li.setAttribute("style", "text-indent:" + item.level * 10 + "px;")
				var a = document.createElement("a");
				var html = "";
				if (item.path && item.path.length)
					html = "<span class=\"ItemPath\">" + item.path + "</span> / ";
				
				//use different classes based on the level
				if (item.level == 0)
					html += "<span class=\"ItemName\">" + item.name + "</span>";
				else
					html += "<span class=\"ItemNameNormal\">" + item.name + "</span>";
				
				if (item.data && item.data.length)
					html += "<span class=\"ItemData\">" + item.data + "</span>";
				
				//set a properties	
				a.href = "javascript:false;";
				a.innerHTML = html;
				li.appendChild(a);
			}
			
			//auto select first item
			if (i == 0)
			{
				this.selectedIndex = 0;
				li.className = "Selected";
			}	
			
			ul.appendChild(li);
		}
	
		this.div.replaceChild(ul,this.div.childNodes[0]);
		
		if (this.matches.length > 0)
		{
			this.reposition();
			this.show();			
		}
		else
			this.hide();

		/********************************************************
		mouseover handler for the dropdown ul
		move the selectedIndex suggestion with the mouse
		********************************************************/
		ul.onmouseover = function(ev)
		{
			//walk up from target until you find the LI.
			var target = me.getEventSource(ev);
			while (target.parentNode && target.tagName.toLowerCase() != "li")
				target = target.parentNode;
			
			if (target)
				me.selectedIndex = parseInt(target.getAttribute("matchindex"));
			me.changeHighlight();
		};

		/********************************************************
		click handler for the dropdown ul
		insert the clicked suggestion into the input
		********************************************************/
		ul.onclick = function(ev)
		{
			me.select();
			me.hide();
			me.cancelEvent(ev);
			return false;
		};
		
	};	
}