(function($) {

	$.fn.dinetoAutocomplete = function(url, htmlId, options, estIdfield) {
		return this.each(function() {
			var $this = $(this);
			
			settings = jQuery.extend({
				clickHandler	: null,
				changeTextBox	: true
			}, options);

			$("body").append("<div id='"+htmlId+"' class='acPopup'></div>");
			
			// Save some variables
			var textBox = $this.get(0);
			textBox.ajaxFile = url;
			textBox.popup = $("#"+htmlId);
			// List items will need access to the textbox
			textBox.popup.get(0).clickHandler = settings.clickHandler;
			textBox.popup.get(0).textBox = $this;
			textBox.isVisible = null;
			textBox.changeTextBox = settings.changeTextBox;
			textBox.phrase = "";
			textBox.hiddenId = (estIdfield != undefined) ? $("#"+estIdfield) : null;
			textBox.inPopup = false;
			
			$this.click($.fn.dinetoAutocomplete.handleMouseClick);
			$this.keydown($.fn.dinetoAutocomplete.handleKeyDown);
			$this.keyup($.fn.dinetoAutocomplete.handleKeyUp);
			$this.bind("removePopup", $.fn.dinetoAutocomplete.removePopup);
		});
	};

	function unescapeHTML(text) {
		return text.replace(/&amp;/g,'&');
	}

	function getList($this) {
		if ($this.val() == "") {
			// Clear the popup
			$this.get(0).popup.html("");
			return;
		}
		$this.addClass("acMakingCall");
		$.post($this.get(0).ajaxFile, {
				action	: "getList",
				phrase	: $this.val()
			}, function (data) {
				$this.removeClass("acMakingCall");
				if (errorDetected(data)) return;
				updatePopup($this, data);
			},
		"json");
	};

	function updatePopup($this, data) {
		var textBox = $this.get(0);
		var $popup = textBox.popup;

		$popup.html(data.html);
		
		// Create event handlers for the list
		$popup.children()
			.hover($.fn.dinetoAutocomplete.itemMouseMove)
			.click($.fn.dinetoAutocomplete.itemMouseClick);
		
		var gotResults = data.html != "";
		
		displayPopup($this, gotResults);
	};

	function displayPopup($this, showNow) {
		var textBox = $this.get(0);
		var $popup = textBox.popup;

		if (textBox.isVisible == null) {
			$popup.css("left", $this.position().left)
				.css("top", $this.position().top+$this.outerHeight())
				.width($this.width());
			textBox.isVisible = false;
		}
		
		if (showNow) {
			if ($popup.html() == "") return;
			$popup.show();
			$this.addClass("acActive");
			$(document).bind("click", removePopup);
		} else {
			$popup.hide();
			$this.removeClass("acActive");
			$(document).unbind("click", removePopup);
		}
		textBox.isVisible = showNow;

	};

	function removePopup() {
		// Since we can't pass anything to this handler, find the autocomplete object that setup this handler
		$(".acActive").trigger("removePopup");
	}

	function moveCursorDown($this) {
		var textBox = $this.get(0);
		var $popup = textBox.popup;

		var $cursor = $popup.find(".cursor");

		if (!textBox.isVisible) {
			if ($cursor.length > 0 && textBox.changeTextBox) {
			  	$this.val( unescapeHTML($cursor.html()) );
			} 
	  		displayPopup($this, true);
			return;
		}
		
		if ($cursor.length == 0) {
			// Set cursor to first entry
			$cursor = $popup.children(":first");
		} else {
			$cursor = $cursor.removeClass("cursor").next();
		}
		
		if ($cursor.length > 0) {
		  	$cursor.addClass("cursor");
			
			if (textBox.changeTextBox) {
				// update the text box value, if requested
			  	$this.val( unescapeHTML($cursor.html()) );
			}
		} else {
		  	$this.val(textBox.phrase);
		}
	};

	function moveCursorUp($this) {
		var textBox = $this.get(0);
		var $popup = textBox.popup;

		var $cursor = $popup.find(".cursor");
		
		if (!textBox.isVisible) {
			if ($cursor.length > 0 && textBox.changeTextBox) {
			  	$this.val( unescapeHTML($cursor.html()) );
			} 
	  		displayPopup($this, true);
			return;
		}
		
		if ($cursor.length == 0) {
			// Set cursor to last entry
			$cursor = $popup.children(":last");
		} else {
			$cursor = $cursor.removeClass("cursor").prev();
		}
		
		if ($cursor.length > 0) {
		  	$cursor.addClass("cursor");
			if (textBox.changeTextBox) {
				// update the text box value, if requested
			  	$this.val( unescapeHTML($cursor.html()) );
			}
		} else {
		  	$this.val(textBox.phrase);
		}
	};
	
	// Event handlers
	$.fn.dinetoAutocomplete.removePopup = function() {
		var $this = $(this);
		var textBox = $this.get(0);
		textBox.value = textBox.phrase;
  		displayPopup($this, false);
	};

	$.fn.dinetoAutocomplete.handleKeyDown = function(event) {
		var $this = $(this);
		var textBox = $this.get(0);
		
		switch (event.keyCode) {
			case 13: // enter
				event.stopPropagation();
				return false;
			case 9:		// tab
				$this.trigger("removePopup");
				break;
			case 40:		// down arrow
				moveCursorDown($this);
				break;
			case 38:		// up arrow
				moveCursorUp($this);
				break;
			case 27:		// esc, restore the phrase
				$this.trigger("removePopup");
				break;
		}
	};

	$.fn.dinetoAutocomplete.handleKeyUp = function(event) {
		var $this = $(this);
		var textBox = $this.get(0);
		var currentPhrase = $this.val();

		if (currentPhrase == "") {
			displayPopup($this, false);
		}
		
		switch (event.keyCode) {
			case 13:		// enter
				if (textBox.isVisible) {
					if (textBox.changeTextBox) {
						var $cursor = textBox.popup.find(".cursor");
						textBox.value = textBox.phrase = unescapeHTML( $cursor.html() );
						// Save the id in a hidden field
						if (textBox.hiddenId != null) textBox.hiddenId.val($cursor.attr("id").replace("e", ""));
					}
					displayPopup($this, false);
				}
				event.stopPropagation();
				return false;
				break;
			default:		// Fetch list of search results
				if (textBox.phrase == currentPhrase) break; // if text didn't change, bail
				if (event.keyCode < 45) return;
			case 8:		// backspace
			case 32:		// space
				textBox.phrase = currentPhrase;
				getList($this);
				// remove the est id from the hiddent box
				if (textBox.hiddenId != null) textBox.hiddenId.val(0);
				break;
		}
		return true;
	};

	$.fn.dinetoAutocomplete.itemMouseMove = function() {
		var $popup = $(this).parents(".acPopup");
		$popup.find(".cursor").removeClass("cursor");
		$(this).addClass("cursor");
	};

	$.fn.dinetoAutocomplete.itemMouseClick = function() {
		var $popup = $(this).parents(".acPopup");
		
		var clickHandler = $popup.get(0).clickHandler;
		if (clickHandler != null) {
			// Call the click handling function if it exists
			clickHandler(this);
		} else {
			// Otherwise just stick the contents of the item in the text box
			var textBox = $popup.get(0).textBox.get(0);
			// update the text box value, if requested
			
			if (textBox.changeTextBox) {
				textBox.value = textBox.phrase = unescapeHTML(this.innerHTML);
				if (textBox.hiddenId != null) textBox.hiddenId.val(this.id.replace("e", ""));
			}
		}
	};
	
})(jQuery);

