/* jQuery Autocomplete
 * Version 1.0
 * Written by Yehuda Katz (wycats@gmail.com) and Rein Henrichs (reinh@reinh.com)
 * @requires jQuery v1.2, jQuery dimensions plugin
 *
 * Copyright 2007 Yehuda Katz, Rein Henrichs
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Modified by namics ag
 * 
 */

/*
 * @description Form autocomplete plugin using preloaded or Ajax JSON data source 
 *
 * @example $('input#user-name').autocomplete({list: ["quentin", "adam", "admin"]})
 * @desc Simple autocomplete with basic JSON data source
 *
 * @example $('input#user-name').autocomplete({ajax: "/usernames.js"})
 * @desc Simple autocomplete with Ajax loaded JSON data source
 *
 */
 
(function($) {
	
	$.ui = $.ui || {}; $.ui.autocomplete = $.ui.autocomplete || {}; var active=null;
		
	$.fn.autocompleteMode = function(container, input, size, opt) {
		var original = input.val(); var selected = -1; var self = this;
		
		$.data(document.body, "autocompleteMode", true);
	
		$("body").one("cancel.autocomplete", function() { 
			input.trigger("cancel.autocomplete"); $("body").trigger("off.autocomplete"); input.val(original); 
		});
		
		$("body").one("elementSelected.autocomplete", function() {
			var obj = false;
			try {
				obj = [$.data(active[0], "originalObject")];
			} catch(e) {
				obj = 'noObject';
			}
			input.trigger("elementSelected.autocomplete", obj);
			$("body").trigger("off.autocomplete");
		});
		
		$("body").one("off.autocomplete", function(e, reset) {
			container.remove();
			$.data(document.body, "autocompleteMode", false);
			input.unbind("keydown.autocomplete");
			$("body").add(window).unbind("click.autocomplete").unbind("cancel.autocomplete").unbind("elementSelected.autocomplete");
		});
		
		// If a click bubbles all the way up to the window, close the autocomplete
		$(window).bind("click.autocomplete", function() { $("body").trigger("cancel.autocomplete"); });

		var select = function() {
			active = $(".jq-ui-autocomplete > *", container).removeClass("active").slice(selected, selected + 1).addClass("active");
			if(active!=null && $(active).length >0) {
				input.trigger("itemSelected.autocomplete", [$.data(active[0], "originalObject")]);     
				if(opt.autoUpdateInputValue) {
					input.val(opt.insertText($.data(active[0], "originalObject")));
				}
			}
		};
		
		container.mouseover(function(e) {
			// If you hover over the container, but not its children, return
			if(e.target == container[0]) return;
			// Set the selected item to the item hovered over and make it active
			selected = $(".jq-ui-autocomplete > *", container).index($(e.target).is('li') ? $(e.target)[0] : $(e.target).parents('li')[0]); select();
		}).bind("click.autocomplete", function(e) {
			$("body").trigger("elementSelected.autocomplete");
			$.data(document.body, "suppressKey", false); 
		});
		
		input
			.bind("keydown.autocomplete", function(e) {
				if(e.which == 27) { $("body").trigger("cancel.autocomplete"); }
				else if(e.which == 13) { $("body").trigger("elementSelected.autocomplete"); }
				else if(e.which == 40 || e.which == 9 || e.which == 38) {
					switch(e.which) {
						case 40: 
						case 9:
							selected = selected >= size - 1 ? 0 : selected + 1; break;
						case 38:
							selected = selected <= 0 ? size - 1 : selected - 1; break;
						default: break;
					}
					select();
				} else { return true; }
				$.data(document.body, "suppressKey", true);
			});
	};
	
	$.fn.autocomplete = function(opt) {
		
		opt = $.extend({}, {
			timeout: 1000,
			autoUpdateInputValue: true,
			getList: function(input) { input.trigger("updateList", [opt.list]); },
			template: function(str) { return "<li>" + opt.insertText(str) + "</li>"; },
			templateLoadingDisplay: '<img src="loading-animation_18px_fast.gif" alt="..loading.." />',
			insertText: function(str) { return str; },
			match: function(typed) { return this.match(new RegExp(typed)); },
			wrapper: "<ul class='jq-ui-autocomplete'></ul>"
		}, opt);

		if($.ui.autocomplete.ext) {
			for(var ext in $.ui.autocomplete.ext) {
				if(opt[ext]) {
					opt = $.extend(opt, $.ui.autocomplete.ext[ext](opt));
					delete opt[ext];
				}
		} }

		return this.each(function() {
			$(this)
				.keypress(function(e) {
					var typingTimeout = $.data(this, "typingTimeout");
					if(typingTimeout) window.clearInterval(typingTimeout);
										
					if($.data(document.body, "suppressKey"))
						return $.data(document.body, "suppressKey", false);
					else if (e.keyCode == 37 || e.keyCode == 39) return true; // fix for left and right arrow
					else if($.data(document.body, "autocompleteMode") && e.charCode < 32 && e.keyCode != 8 && e.keyCode != 46) return false;          
					else {
						$.data(this, "typingTimeout", window.setTimeout(function() { 
							$(e.target).trigger("autocomplete"); 
						}, opt.timeout));
					}
				})
				.bind("autocomplete", function() {
					var self = $(this);
					// prevent empty requests
					if(self.val()=='') return false;
					
					var container = null;
					var showContainer = function(content) {
						container = $(content).wrapAll(opt.wrapper).parents(":last").children();
						
						var offset = self.offset({border: false, padding: false});
						
						var leftPos = offset.left;
						var topPos = offset.top + self.outerHeight();

						// ie fix - dimensions in IE are not correct
						if ($.browser.msie) {
							topPos = topPos -2;
							leftPos = leftPos - 2;
						}
											
						opt.container = container
							.css({top: topPos, left: leftPos, width: self.width(), position: 'absolute'})
							.addClass('jq-ui-autocomplete-wrap')
							.appendTo("body");
							
						return container;
					}

					self.one("showLoadingDisplay", function(e) {
						showContainer(opt.templateLoadingDisplay);
					});
						
					self.one("updateList", function(e, list) {
						list = $(list)
							.filter(function() { return opt.match.call(this, self.val()); })
							.map(function() {
								var node = $(opt.template(this))[0];
								$.data(node, "originalObject", this);
								return node; 
							});

						$("body").trigger("off.autocomplete");
					
						if(!list.length) return false;
						
						$('.jq-ui-autocomplete', opt.container).html(list);
					
						//var container = showContainer(list);
					
						$("body").autocompleteMode(container, self, list.length, opt);
					});

					opt.getList(self);
				});

		});
	};
	
})(jQuery);
