/*
 * exaSuggest jQuery plugin
 * @author christophe.jean[at]exalead.com
 * @version 1.2
 */
"use strict";
(function($) {
	if ($.fn.exaSuggest === undefined) {
		$.fn.exaSuggest = function(options) {

			var KEY = {
				UP: 38,
				DOWN: 40,
				ESC: 27,
				ENTER: 13
			};

			var defaults = {
				url: 'suggest.php',
				autosubmit: true,
				delay: 500,
				showDelay: 0,
				hideDelay: 0,
				showFirstEntry: false,
				cache: true
			};

			options = $.extend(defaults, options);

			return this.each(function() {

				var selectElement = function(element) {
					suggest.find(".selected").removeClass("selected");
					element.addClass("selected");
				};

				var selectPrevious = function() {
					var current = suggest.find(".selected");
					if (current === undefined || current.prev().length === 0) {
						current = suggest.find("li:last");
					} else {
						current = current.prev();
					}
					selectElement(current);
					searchField.val(current.text());
				};

				var selectNext = function() {
					var current = suggest.find(".selected");
					if (current === undefined || current.next().length === 0) {
						current = suggest.find("li:first");
					} else {
						current = current.next();
					}
					selectElement(current);
					searchField.val(current.text());
				};

				var submitText = function(text) {
					searchField.val(text);
					searchField.focus();
					suggest.slideUp(options.hideDelay);
					if (options.autosubmit) {
						searchField.parents("form").submit();
					}
				};

				var showSuggestData = function(data) {
					suggest.empty();
					if (options.showFirstEntry) {
						data = [searchField.val()].concat(data);
					}
					var regex = new RegExp("(" + searchField.val() + ")","i");
					for (var word in data) {
						var nElement = $('<li>' + data[word].replace(regex, '<span class="highlighted">$1</span>') + '</li>');
						nElement.click(function(event){
							selectElement($(this));
							submitText($(this).text());
							event.preventDefault();
						});
						nElement.mouseenter(function(event){
							selectElement($(event.target));
						});
						suggest.append(nElement);
					}
					if (data.length > 0 && query.length > 0) {
						suggest.slideDown(options.showDelay);
					}

				};

				var searchField = $(this).attr("autocomplete", "off");
				var query = searchField.val();
				var suggest = $('<ul class="autocomplete" />');
				if (options.cache) {
					suggest.data("cache",[]);
				}
				suggest.insertAfter( searchField );

				suggest.drawUnder = function(parent) {
					var width = parent.outerWidth();
					var element = $(this);
					width -= parseInt(element.css("borderLeftWidth")) + parseInt(element.css("paddingLeft"), 10);
					width -= parseInt(element.css("borderRightWidth")) + parseInt(element.css("paddingRight"), 10);
					element.width(width);
					return element.css({
						"top" : parent.position().top + parent.outerHeight(),
						"left" : parent.position().left
					});
				};

				suggest.drawUnder(searchField);

				var timeout = null;

				searchField.blur(function(){
					window.setTimeout(function(){
						suggest.slideUp(options.hideDelay);
					},200);
				});

				searchField.keyup(function(event){
					var key = event.keyCode;
					if (key !== KEY.UP && key !== KEY.DOWN && query !== searchField.val() && searchField.val().length > 0) {
						query = searchField.val();
						clearTimeout(timeout);
						if (!options.cache || suggest.data("cache")[query] === undefined){
							timeout = window.setTimeout(function(){
								$.ajax({
									type: "GET",
									cache: true,
									data: "q=" + escape(query),
									dataType: "json",
									url: options.url,
									success: function(data){
										if (options.cache) {
											suggest.data("cache")[query] = data;
										}
										showSuggestData(data);
									}
								});
							},options.delay);
						} else {
							showSuggestData(suggest.data("cache")[searchField.val()]);
						}
					} else {
						query = searchField.val();
						if (query.length === 0) {
							suggest.slideUp(options.hideDelay);
						}
					}

				});

				searchField.keydown(function(event){
					if (suggest.is(":visible")) {
						var key = event.keyCode;
						if (key === KEY.ESC) {
							suggest.slideUp(options.hideDelay);
							event.preventDefault();
						} else if (key === KEY.UP) {
							selectPrevious();
						} else if (key === KEY.DOWN) {
							selectNext();
						} else if (key === KEY.ENTER) {
							submitText(searchField.val());
							event.preventDefault();
						}
					}
				});

				$(window).resize(function(){
					suggest.drawUnder(searchField);
				});
			});
		};
	} else {
		throw new Error("jquery.exaSuggest() is already defined");
	}
})(jQuery);
