jQuery.fn.autocomplete2 = function(resource, settings)
{
	settings = jQuery.extend(
	{
		delay: 400,
		minChars: 1,
		of: 'of',
		choicesId: 'autocomplete-choices',
		overClass: 'over',
		indicator: null
	}, settings);
	
	var $choices = jQuery('<div>');
	$choices.hide().css('position', 'absolute');
	$choices.hide().css('background', '#ffffff');
	$choices.attr('id', settings.choicesId);
	$choices.appendTo('body');
	
	/*if (settings.indicator != null)
	{
		jQuery("#" + settings.indicator).ajaxStart(function()
		{
			jQuery(this).show();
		}).ajaxStop(function()
		{
			jQuery(this).hide();
		});
	}*/
	
	this.each(function()
	{
		var input = this;
		var $input = jQuery(input).attr('autocomplete', 'off');
		var hasFocus = false;
		var choices = new Array;
		var active = 0;
		var cacheData = new Array;
		var cacheDimensions = new Array;
		var timeout;
		
		$input.keydown(function(e)
		{
			a = e.keyCode;
			switch(e.keyCode)
			{
				case 38: // up
					e.preventDefault();
					moveSelect(-1);
					break;
				case 40: // down
					e.preventDefault();
					moveSelect(1);
					break;
				//case 9: // tab
				case 13: // enter
					e.preventDefault();
					selectCurrent();
					hideChoices();
					$input.blur();
					break;
				case 27: // escape
					e.preventDefault();
					hideChoices();
					break;
				default:
					if (timeout) clearTimeout(timeout);
					timeout = setTimeout(function(){ typed(a); }, settings.delay);
					break;
			}
		}).focus(function()
		{
			hasFocus = true;
		}).blur(function()
		{
			hasFocus = false;
			hideChoices();
		});
		
		var moveSelect = function(step)
		{
			var lis = jQuery('li', $choices);
			var size = lis.size() - 1;
			
			active = active + step;
			active = (active < 0) ? 0 : active;
			active = (active >= size) ? size : active;
			
			lis.removeClass(settings.overClass);
			jQuery(lis[active]).addClass(settings.overClass);
		}
		
		var hideChoices = function()
		{
			active = 0;
			choices = new Array;
			$choices.hide();
		}
		
		var showChoices = function(choices, size)
		{
			fillChoices(choices);
			
			if (choices.length < size)
			{
//alert (""+choices.length+" =!= "+size);
				var p = jQuery("<p>");
				p.text(choices.length + " " + settings.of + " " + size);
				p.appendTo($choices);
			}
			
			$choices.css('top', $input.offset().top + $input.offset().scrollTop + $input.outerHeight());
			$choices.css('left', $input.offset().left + $input.offset().scrollLeft);
			$choices.css('width', $input.width());
//			$choices.show();
		}
		
		var fillChoices = function(choices)
		{
			var ul = jQuery('<ul>');
			var l = document.getElementById("s-"+input.id);
			l.options.length = 0;

			for (i in choices)
			{
//alert(typeof(choices[i]));
				if (typeof(choices[i]) == 'string')
				{
					var item = jQuery('<li>').text(choices[i]).appendTo(ul);
					
					item.mousedown(function()
					{
						var index = jQuery("li", ul).index(this);
						
						moveSelect(index);
						selectCurrent();
					});
					
					if (i == 0) item.addClass(settings.overClass);
				}

				if (typeof(choices[i]) == 'object')
				{
					l.options.length++;
					l.options[l.options.length-1].text = choices[i].name;
					l.options[l.options.length-1].value = choices[i].id;
				}

			}
			
			$choices.html('');
			ul.appendTo($choices);
		}
		
		var selectCurrent = function()
		{
			var item = jQuery('li.' + settings.overClass, $choices);
			$input.val(item.text());
		}
		
		var typed = function(e)
		{
			if (e == 46 || (e > 8 && e < 32)) hideChoices();
			
			if ($input.val().length >= settings.minChars)
			{
				requestData($input.val());
			}
			else
			{
				hideChoices();
			}
		}
		
		var requestData = function(q)
		{
			if (settings.indicator != null)
			{
				jQuery("#" + settings.indicator).show();
			}
			jQuery("#" + settings.indicator+"_no").hide();

			uri = resource + q;
			
			var res = searchInCache(q);
			var size = cacheDimensions[q];
			
			if (res.length > 0)
			{
				showChoices(res, size);
				if (settings.indicator != null)
				{
					jQuery("#" + settings.indicator).hide();
				}
			}
			else
			{
				jQuery.getJSON(uri, function(result)
				{
//alert(typeof(result.data));
					if (typeof(result.data) != undefined)
					{
						choices = result.data;
//alert(choices.length);
						if (choices.length > 0 )
						{
//alert(result.size);
							showChoices(choices, result.size);
							addToCache(q, choices, result.size);
						}

						if (result.cnt == 0)						
						{							
							jQuery("#" + settings.indicator+"_no").show();
							hideChoices();
						}
					}
					if (settings.indicator != null)
					{
						jQuery("#" + settings.indicator).hide();
					}
				});
			}
		}
		
		var addToCache = function(q, choices, size)
		{
			var re = new RegExp(q, 'i');
			
			if (cacheData.length == 0)
			{
				cacheData[q] = choices;
				cacheDimensions[q] = size;
			}
			else
			{
				for (i in cache)
				{
					if (!re.test(i))
					{
						cacheData[q] = choices;
						cacheDimensions[q] = size;
					}
				}
			}
		}
		
		var searchInCache = function(q)
		{
			/*
			var temp = new Array;
			var output = new Array;
			*/
			
			/*
			for (i in cacheData)
			{
				var rei = new RegExp(i, 'i');
				if (i.length <= q.length && rei.test(q))
				{
					for (j in cacheData[i])
					{
						if (typeof(cacheData[i][j]) == "string")
						{
							var rej = new RegExp(q, 'i');
							var res = cacheData[i][j].match(rej);
							if (res != null)
							{
								temp[cacheData[i][j]] = 1;
							}
						}
					}
				}
			}
			
			for (i in temp)
			{
				if (typeof(i) == 'string')
				{
					output.push(i);
				}
			}
			*/
			
			if (typeof(cacheData[q]) != "undefined")
			{
				return cacheData[q];
			}
			else
			{
				return new Array();
			}
		}
		
	});
	return this;
}