jQuery.fn.autocomplete = function(url, settings ) 
{
	return this.each( function()
	{
		var textInput = $(this);
		textInput.after('<ul class="autocomplete"></ul>');
		var list = textInput.next().css({width: textInput.width()});
		var selected = -1;
		var data = Array();
		var typingTimeout;
		var origText;
		settings = jQuery.extend(
		{
			minChars : 2,
			timeout: 100,
			cityID: null,
			regionID: null,
			maxSuggestions: null
		}, settings);
		preLoadData(url);
		function preLoadData(url)
		{
			$.getJSON(url,{}, function(response) { data = response; } );
		}
		function findMatches()
		{
			var textMatch = textInput.val();
			hideList();
			clearResults();
			
			if ( textMatch.length >= settings.minChars && textMatch != origText )
			{
				var found = 0;
				$.each(data, 
					   function(i,item) {
							if ( item.title.toLowerCase().indexOf(textMatch.toLowerCase()) > -1 )
							{
								list.append(buildListItem(item, i, textMatch));
								found++;
							}
							if (settings.maxSuggestions && found >= settings.maxSuggestions )
							{
							   return false;
							}
					   }
					   );
				if ( list.children().length > 0 )
				{
					list.show().children().hover(
									function() { 
										$(this).addClass("selected").siblings().removeClass("selected");
									},
									function() { 
										$(this).removeClass("selected") 
									} 
								).click( function () {
												selectField($(this).attr('value'));
												hideList();
											}
									);
				}
				
			}
			origText = textMatch;
		}
		
		function hideList()
		{
			list.hide();
			list.html("");
			selected = -1;
		}
		function buildListItem(dataItem, index, searchString)
		{
			var output =  '<li value="' + index + '"><div class="name">' + dataItem.title.replace(new RegExp("(" + searchString + ")","i"),"<strong>$1</strong>") + '</div>';
			if ( dataItem.city_id > 0 )
			{
				output += '<div class="region">, ' + dataItem.region + '</div>';
			}
			output += ' <div class="count">(' + dataItem.count + ' Hotels)</div></li>';
			return output;			
		}
		
		function selectField(index)
		{
			textInput.val(data[index].title);
			if ( settings.cityField )
			{
				$(settings.cityField).val(data[index].city_id);
			}
			
			if ( settings.regionField )
			{
				$(settings.regionField).val(data[index].region_id);
			}
		}
		
		function clearResults()
		{
			if ( settings.cityField )
			{
				$(settings.cityField).val(0);
			}
			
			if ( settings.regionField )
			{
				$(settings.regionField).val(0);
			}
		}
		//Catch Key Down Event on input text box
		textInput.keydown(function(e) 
		{
			window.clearInterval(typingTimeout);
			var selectionCount = list.children().length;
			switch ( e.which )
			{
				case 27 : //ESC
						textInput.val(origText);
						clearResults();
						hideList();
					break;
				case 13 : //Return
						if ( selectionCount > 0 )
						{
							hideList();
							e.preventDefault();
							return false;
						}
					break;
					
				case 9 : // Tab
						hideList();
					break;
				case 38 : // Up Arrow
						if ( selected <= 0 )
						{
							selected = selectionCount;
						}
						selected--;
						selectField(list.children().removeClass('selected').eq(selected).addClass('selected').attr('value'));
					break;
				case 40 : // Down Arrow
						if ( selected >= (selectionCount-1) )
						{
							selected = -1;
						}
						selected++;
						selectField(list.children().removeClass('selected').eq(selected).addClass('selected').attr('value'));
					break;
				case 37 :
				case 39 :
					break;
				default: 
						typingTimeout = window.setTimeout(
															function() { 
																findMatches() 
															},
															settings.timeout
														);
					break;
			}
		});
		
		//
	});
}