var suggestions = {
	"maxHeight":150,
	"searchIndex":-1,
	"getOffset":function() {
		if (!arguments[0]) return [0,0];
		var obj = arguments[0];
		var offset = [obj.offsetLeft,obj.offsetTop];
		var parent = obj;
		while (parent != null) {
			if (obj.offsetParent) {
				parent = obj.offsetParent;
				if (parent.offsetLeft) offset[0] += parseFloat(parent.offsetLeft);
				if (parent.offsetTop) offset[1] += parseFloat(parent.offsetTop);
				obj = parent;
			} else {
				return offset;
			}
		}
	},
	"clearResults":function(results,crutch) {
		if (typeof(results)=="string") results = document.getElementById(results);
		if (typeof(crutch)=="string") crutch = document.getElementById(crutch);
		if (!results) results = document.getElementById('suggestions');
		if (!crutch) crutch = document.getElementById('suggestCrutch');
		if (!results || !crutch) return;
		if (results && results!=document.activeElement) {
			results.style.visibility = "hidden";
			if (crutch) crutch.style.visibility = "hidden";
		}
	},
	"selectItem":function(obj,item,results,crutch) {
		if (!obj || !item || !results) return;
		obj.rel = item.innerHTML;
		obj.value = item.innerHTML;
		results.style.visibility = "hidden";
		if (crutch) crutch.style.visibility = "hidden";
		if (document.all) {
			setTimeout(function() {
				var range = obj.createTextRange();
				range.moveStart('character',obj.value.length);
				range.moveEnd('character',0);
				range.select();
			},100);
		} else {
			setTimeout(function(){ obj.focus() },100);
		}
	},
	"getSuggestions":function(handler,url) {
		if (!handler || typeof(handler)!="function" || !url) return;
		var sockets = ["Msxml2.XMLHTTP.6.0","Msxml2.XMLHTTP.5.0","Msxml2.XMLHTTP.4.0","Msxml2.XMLHTTP.3.0","Msxml2.XMLHTTP","Microsoft.XMLHTTP"];
		var socket = (window.XMLHttpRequest)?new XMLHttpRequest():null;
		if (!socket) {
			for (var c=0; c<sockets.length; c++) {
				try {
					socket = new ActiveXObject(sockets[c]);
					break;
				} catch(e) {}
			}
		}
		if (!socket) return;
		socket.onreadystatechange = function() {
			if (socket.readyState==4 && socket.status==200) {
				var data = socket.responseText.split("\n");
				handler(data);
			}
		}
		socket.open("GET",url,true);
		socket.send(null);
	},
	"suggest":function(e,obj,source,results,crutch,maxMatches,handler) {
		if (typeof(results)=="string") results = document.getElementById(results);
		if (typeof(crutch)=="string") crutch = document.getElementById(crutch);
		if (!results) results = document.getElementById('suggestions');
		if (!crutch) crutch = document.getElementById('suggestCrutch');
		if (!obj || !source || !results || !crutch) return;
		if (!e) e = window.event;
		if (!maxMatches) maxMatches = 100;
		var input = obj.value.replace(/([^a-zA-Z0-9_])/g,"\\$1").replace(/\s(\s+)/g," ");
		var regX = new RegExp("^"+input,"i");
		var divs = results.getElementsByTagName('div');
		var matches = [];
		if (obj.value == "") {
			obj.rel = "";
			results.style.visibility = "hidden";
			if (crutch) crutch.style.visibility = "hidden";
			return true;
		}
		if (e.keyCode == 38) {
			if (divs.length==0) return;
			if (searchIndex == -1) {
				searchIndex = divs.length-1;
			} else {
				searchIndex--;
			}
			for (var c=0; c<divs.length; c++) {
				divs[c].className = "";
			}
			if (searchIndex <= -1) {
				searchIndex = divs.length;
				obj.value = obj.rel;
			} else {
				divs[searchIndex].className = "selected";
				obj.value = divs[searchIndex].innerHTML;
				if (divs[searchIndex].offsetTop >= suggestions.maxHeight) {
					results.scrollTop = divs[searchIndex].offsetTop;
				} else {
					results.scrollTop = 0;
				}
			}
		} else if (e.keyCode == 40) {
			if (divs.length==0) return;
			if (searchIndex == divs.length) {
				searchIndex = 0;
			} else {
				searchIndex++;
			}
			for (var c=0; c<divs.length; c++) {
				divs[c].className = "";
			}
			if (searchIndex > divs.length-1) {
				searchIndex = -1;
				obj.value = obj.rel;
			} else {
				divs[searchIndex].className = "selected";
				obj.value = divs[searchIndex].innerHTML;
				if (divs[searchIndex].offsetTop >= suggestions.maxHeight) {
					results.scrollTop = divs[searchIndex].offsetTop;
				} else {
					results.scrollTop = 0;
				}
			}
		} else if (e.keyCode == 13) {
			if (results.style.visibility=="hidden" || !results.style.visibility) {
				if (handler && typeof(handler)=="function") handler();
				return;
			}
			if (divs.length==1 || divs[0].innerHTML.toLowerCase()==obj.value.toLowerCase()) {
				suggestions.selectItem(obj,divs[0],results,crutch);
			} else {
				if (searchIndex < 0) return;
				obj.rel = obj.value;
				results.style.visibility = "hidden";
				if (crutch) crutch.style.visibility = "hidden";
			}
		} else if (e.keyCode == 27) {
			obj.value = obj.rel;
			results.style.visibility = "hidden";
			if (crutch) crutch.style.visibility = "hidden";
			return true;
		} else {
			try {
				if (obj.value==obj.rel||(divs[searchIndex]&&searchIndex>-1&&obj.value==divs[searchIndex].innerHTML)) return true;
			} catch(e) {}
			obj.rel = obj.value;
			results.innerHTML = "";
			searchIndex = -1;
			for (var c=0; c<source.length; c++) {
				if (maxMatches>-1 && matches.length>=maxMatches) break;
				if (source[c].match(regX)) matches.push(source[c]);
			}
			if (matches.length>0) {
				if (matches.length==1 && obj.value==matches[0]) return;
				for (var c=0; c<matches.length; c++) {
					if (!matches[c]) break;
					var div = document.createElement('div');
					div.onmousedown = function() {
						suggestions.selectItem(obj,this,results,crutch);
					}
					div.onmouseover = function() {
						if (!this.className.match(/\s*(selected|hover)/)) this.className += " hover";
					}
					div.onmouseout = function() {
						this.className = this.className.replace(/\s*hover/g,"");
					}
					div.style.cursor = "pointer";
					div.innerHTML = matches[c];
					results.appendChild(div);
				}
				var offset = suggestions.getOffset(obj);
				results.style.width = (obj.offsetWidth-((document.compatMode=="CSS1Compat")?2:0)) + "px";
				results.style.height = "auto";
				results.style.left = offset[0] + "px";
				results.style.top = (offset[1]+obj.offsetHeight) + "px";
				if (results.offsetHeight>suggestions.maxHeight) results.style.height = suggestions.maxHeight + "px";
				results.style.visibility = "visible";
				if (document.all && crutch) {
					crutch.style.left = results.style.left;
					crutch.style.top = results.style.top;
					crutch.style.height = results.offsetHeight + "px";
					crutch.style.width = results.offsetWidth + "px";
					crutch.style.visibility = "visible";
				}
			} else {
				results.style.visibility = "hidden";
				if (crutch) crutch.style.visibility = "hidden";
			}
		}
	}
};