var AutoComplete = 
{
	fetchProposals : function (sWord, sObjectId, fCallback)
	{
		if (!sWord) return;
		var r = Utils.Http.createRequest();
		if (r)
		{
			r.onreadystatechange = function ()
			{
				if (Utils.Http.isReady(r))
				{
					var s = Utils.Http.getResponseText(r);
					var proposals = [];
					if (s && s.length)
					{
						var matches = eval('(' + s + ')');
						for (var i = 0, l = matches.length; i < l; ++i)
						{
							proposals[i] = Utils.htmlUnescape(matches[i].value);
						}
					}
					fCallback(proposals);
				}
			}
			r.open(
				'GET',
				'ajax.php?object=' + sObjectId + '&json=1&call=getProposals&arg0=' + sWord,
				true
			);
			r.send(null);
		}
	},
	
	show : function (oElement)
	{
		if (oElement.autocomplete.visible) return;
		oElement.autocomplete.visible = true;
		oElement.autocomplete.hidden = Utils.Screen.hideElements(
			['iframe', 'object', 'embed']
		);
		var pos = Utils.Screen.getElementPosition(oElement);
		Utils.Dom.setState(
			oElement.autocomplete.list,
			{
				style : 
				{
					position : 'absolute',
					top : (pos.top + pos.height) + 'px',
					left : pos.left + 'px',
					width : pos.width + 'px',
					zIndex : 1000,
					display : 'block'
				}
			}
		);
	},
	
	hide : function (oElement)
	{
		if (!(oElement && oElement.autocomplete && oElement.autocomplete.visible))
			return;
		oElement.autocomplete.visible = false;
		oElement.autocomplete.list.style.display = 'none';
		Utils.Screen.showElements(oElement.autocomplete.hidden);
	}, 
	
	select : function (oElement, nSelected)
	{
		if (!(oElement.autocomplete.proposals && oElement.autocomplete.proposals.length))
			return;
		oElement.autocomplete.list.childNodes[oElement.autocomplete.selected].className = 'autocomplete';
		if (nSelected < 0) nSelected = 0;
		if (nSelected >= oElement.autocomplete.proposals.length)
		{
			nSelected = oElement.autocomplete.proposals.length - 1;
		}
		oElement.autocomplete.selected = nSelected;
		oElement.autocomplete.list.childNodes[oElement.autocomplete.selected].className = 'autocomplete_selected';
	},
	
	update : function (oElement, aProposals)
	{
		oElement.autocomplete.proposals = aProposals;
		if (aProposals.length)
		{
			oElement.autocomplete.list.innerHTML = '';
			for (var i = 0, l = aProposals.length; i < l; ++i)
			{
				var li = $C('li');
				li.className = 'autocomplete';
				li.innerHTML = aProposals[i].replace(
					new RegExp('(^' + oElement.value + ')', 'ig'),
					'<strong>$1</strong>'
				)
				oElement.autocomplete.list.appendChild(li);
				li.input = oElement;
				li.number = i;
				Utils.Events.addListener(li, 'mouseover', AutoComplete.onMouseOver);
				Utils.Events.addListener(li, 'click', AutoComplete.onClick);
			}
			AutoComplete.select(oElement, 0);
			AutoComplete.show(oElement);
		}
		else
		{
			AutoComplete.hide(oElement);
		}
	},
	
	changed : function (oEvent, oSource)
	{
		if (oSource.value.length)
		{
			if (oSource.value != oSource.autocomplete.prevValue)
			{
				if (oSource.autocomplete.timer != null)
					clearTimeout(oSource.autocomplete.timer);
				oSource.autocomplete.timer = setTimeout(
					function ()
					{
						AutoComplete.fetchProposals(
							oSource.value,
							oSource.id,
							function (aProposals)
							{
								AutoComplete.update(oSource, aProposals);
							}
						);
					},
					300
				);
				oSource.autocomplete.prevValue = oSource.value;
			}
		}
		else AutoComplete.hide(oSource);
	},
	
	applySelected : function (oElement)
	{
		if (oElement.autocomplete.proposals && oElement.autocomplete.proposals.length && (oElement.autocomplete.selected < oElement.autocomplete.proposals.length))
		{
			oElement.value = oElement.autocomplete.proposals[oElement.autocomplete.selected];
			oElement.blur();
		}
	},
	
	onMouseOver : function (oEvent, oSource)
	{
		AutoComplete.select(oSource.input, oSource.number);
	},
	
	onClick : function (oEvent, oSource)
	{
		AutoComplete.applySelected(oSource.input);
	},
	
	onKeyUp : function (oEvent, oSource)
	{
		var eventData = Utils.Events.process(oEvent);
		switch (eventData.keyCode)
		{
			case 13:
				AutoComplete.applySelected(oSource);
				break;
			case 38:
			case 40:
				break;
			default:
				AutoComplete.changed(oEvent, oSource);
				return true;
				break; 
		}
		oEvent = Utils.Events.kill(oEvent);
		return false;
	},
	
	onKeyPress : function (oEvent, oSource)
	{
		var eventData = Utils.Events.process(oEvent);
		switch (eventData.keyCode)
		{
			case 13:
				break;
			case 38:
				AutoComplete.select(oSource, oSource.autocomplete.selected - 1);
				break;
			case 40:
				AutoComplete.select(oSource, oSource.autocomplete.selected + 1);
				break;
			default:
				return true;
				break;
		}
		oEvent = Utils.Events.kill(oEvent);
		return false;
	},
	
	onBlur : function (oEvent, oSource)
	{
		setTimeout('AutoComplete.hide($(\'' + oSource.id + '\'))', 100);
	},
	
	initElement : function (oElement)
	{
		if (!oElement.autocomplete)
		{
			var oListElement = $C('ul');
			oListElement.className = 'autocomplete';
			oListElement.style.display = 'none';
			oElement.autocomplete =
			{
				prevValue : oElement.value,
				proposals : 0,
				list : oListElement,
				selected : 0,
				visible : false,
				hidden : [],
				timer : null
			}
			Utils.Events.addListener(oElement, 'keyup', AutoComplete.onKeyUp);
			Utils.Events.addListener(oElement, 'keypress', AutoComplete.onKeyPress);
			Utils.Events.addListener(oElement, 'blur', AutoComplete.onBlur);
			document.getElementsByTagName('body')[0].appendChild(oListElement);
		}
	},

	refresh : function ()
	{
		var elements = Utils.Dom.getElementsByClassName('autocomplete');
		for (var i = 0, l = elements.length; i < l; ++i)
		{
			AutoComplete.initElement(elements[i]);
		}
	},

	init : function (c)
	{
		if (10 < ++c) return; 
		var ex;
		try
		{
			Utils.Events.addListener(window, 'load', AutoComplete.refresh);
		}
		catch (ex)
		{
			setTimeout('AutoComplete.init(' + c + ')', 1000);
		}
	}
};

AutoComplete.init(0);