/*
 * This is an adaptation of http://www.pengoworks.com/workshop/jquery/autocomplete.htm
 * which in turn is a modification of Dan Verheul's jQuery Autocomplete plugin.
 */

jQuery.autocomplete = function(input, options)
{
	var $input = $(input).attr("autocomplete", "off");

	// Create results
	var results = document.createElement("div");
	var $results = $(results);
	$results.hide().addClass(options.resultsClass).css("position", "absolute");

	if (options.width > 0) $results.css("width", options.width);

	$("body").append(results);

	var timeout = null;
	var selected_index = null;
	var active = -1;
	var entered_text = '';
	var lastKeyPress = null;

	$input.keyup(function(e){
		entered_text = $input.val();
		lastKeyPress = e.keyCode
		switch(e.keyCode)
		{
			case 38: // up
				moveSelect(-1);
				break;

			case 40:
				moveSelect(1);
				break;
			
			case 13: // Return
				hideResults();
				break;

			case 9: // Tab
			case 8: // backspace
				// Do Nothing
				break;

			default:
				active = -1;
				if (timeout) clearTimeout(timeout);
				timeout = setTimeout(onChange, options.delay);
				break;
		}
	});

	$input.blur(function() {
		var lis = $("li", results);
		var matched_segment = lis[active].selectValue.substring(0, entered_text.length).toLowerCase();
		var entered_text_lower = entered_text.toLowerCase();


		if (matched_segment == entered_text_lower)
		{
			selectItem(lis[active]);
		}
		
		hideResults();
	});

	function onChange()
	{
		requestData();
		showResults();
	}

	function selectItem(li, donthide)
	{
		$input.val(li.selectValue);
	}

	function dataToDom(data)
	{
		var ul = document.createElement("ul");
		
		for (row in data)
		{
			var li = document.createElement("li");
			li.innerHTML = data[row];
			li.selectValue = data[row];
			ul.appendChild(li);

			$(li).hover(
				function(){ 
					$("li", ul).removeClass(options.hoverClass); 
					$(this).addClass(options.hoverClass); 
					active = $("li", ul).indexOf($(this).get(0));
				},
				function(){ $(this).removeClass(options.hoverClass); }
			).click(function(e){ e.preventDefault(); e.stopPropagation(); selectItem(this); });
		}
		return ul;
	}

	function handleData(data)
	{
		$results.html("");
		var new_data = options.data_callback(data);
		if (new_data.length == 0)
		{
			hideResults(true);
		}	else {
			$results.append(dataToDom(new_data));
		}
		moveSelect(0);
	}

	function requestData()
	{
		var url = options.url_callback($input.val());
		$.getJSON(url, handleData);
	}

	function showResults()
	{
		var pos = findPos(input);
		var iWidth = (options.width > 0) ? options.width : $input.width();
		$results.css({
			width: (parseInt(iWidth)) + "px",
			top: (pos.y + input.offsetHeight - 2) + "px",
			left: (pos.x) + "px"
		}).show();
	}

	function moveSelect(step)
	{
		var lis = $("li", results);
		if(lis.length == 0) return;

		active += step;
		if (active < 0)
		{
			active = 0;
		} else if (active >= lis.size()) {
			active = list.size() - 1;
		}

		lis.removeClass(options.hoverClass);
		$(lis[active]).addClass(options.hoverClass);
	}

	function hideResults(now)
	{
		if (now)
		{
			$results.hide();
		} else {
			if (timeout) clearTimeout(timeout);
			timeout = setTimeout(function(){hideResults(true);}, 200);
		}
	}

	function selectText(start, end)
	{
		var field = $input.get(0);
		if( field.createTextRange ){
			var selRange = field.createTextRange();
			selRange.collapse(true);
			selRange.moveStart("character", start);
			selRange.moveEnd("character", end);
			selRange.select();
		} else if( field.setSelectionRange ){
			field.setSelectionRange(start, end);
		} else {
			if( field.selectionStart ){
				field.selectionStart = start;
				field.selectionEnd = end;
			}
		}
	}

	function findPos(obj) {
		var curleft = obj.offsetLeft || 0;
		var curtop = obj.offsetTop || 0;
		while (obj = obj.offsetParent) {
			curleft += obj.offsetLeft
				curtop += obj.offsetTop
		}
		return {x:curleft,y:curtop};
	}
}

jQuery.fn.autocomplete = function(url_callback, data_callback, options)
{
	options = options || {};

	options.url_callback = url_callback;
	options.data_callback = data_callback;

	this.each(function() {
		var input = this;
		new jQuery.autocomplete(input, options)
	});

	return this;
}

jQuery.fn.indexOf = function(e){
	for( var i=0; i<this.length; i++ ){
		if( this[i] == e ) return i;
	}
	return -1;
};

