/**
 * Highlights an autocomplete entry.
 * 
 * @param needle input value
 * @param haystack string to search
 * @return highlighted entry from the list
 */
function autocomplete_highlight(needle,haystack) {
	
	var exps = needle.replace(/^\s+/,'').replace(/\s+$/,'').split(" ");

	jQuery.each(exps, function(j, expvals) {

		var regex = new RegExp(expvals,'gi');
		
		var exre = regex.exec(haystack);
		
		var matches = new Array();
		
		while (exre !== null) {
		
			matches.push(haystack.slice(exre.index,exre.index + expvals.length));

			exre = regex.exec(haystack);
			
		}
		
		jQuery.each(matches, function(i, vals) {
		
			haystack = haystack.replace(vals,'<b><u>' + vals + '</u></b>');
			
		});
		
	});
	
	return haystack;
	
}

(function($){
	
	/**
	 * JQuery PlugIn: autocomplete
	 */
	$.fn.autocomplete = function(options) {
		
		var defaults = {
				delay : 1500,
				letters : 2,
				show : 4,
				cache : true,
				url : null,
				limit : 20,
				array : new Array(),
				arraystring : '',
				loadingimage : {
					url : '/img/ui/loading.png',
					width : 59,
					height : 26
				},
				listClass : 'ac_list',
				output : function(val,obj) {
			
					return val;
			
				},
				select : function(val,obj,input,node) {

					return val;
					
				},
				error: function(obj) {
				
					return;
					
				}

		};
		
		var options = $.extend(defaults, options);
		
		return this.each(function() {
			
			var obj = $(this);
			
			var objid = obj.attr('id');
			
			var thread = null;
			
			var cache = new Object();
			
			function dropdown(pArray) {
				
				if(pArray == 0) {
				
					obj.css('background-image','url()');
					defaults.error(obj);
					return;
					
				}
				
				var objPosition = obj.position();

				var height = 0;
				
				var inheight = 0;
				
				obj.after('<div class="'+defaults.listClass+'" id="'+objid+'ddlist" style="position:absolute;top:'+(objPosition.top+28)+'px;left:'+(objPosition.left)+'px;width:'+obj.innerWidth()+'px;height:100px;"></div>');
				
		        jQuery.each(pArray, function(i, val) {
		        	
		        	$('#'+objid+'ddlist').append('<div class="ac_unsel"><a href="javascript:void(0)">'+defaults.output(val,obj)+'</a></div>');
		        	
		        	if(i<defaults.show) {
		        	
		        		height += $('#'+objid+'ddlist div').innerHeight() + 1;
		        	
		        	}
		        	
		        	cache[obj.val()][i].__top = inheight;
		        	
		        	inheight += $('#'+objid+'ddlist div').outerHeight(true);
		        	
		        });
		        
		        $('#'+objid+'ddlist').height(height);
		        
		        $('#'+objid+'ddlist').mouseenter(function() {
		        	
		        	$('#'+objid+'ddlist div').removeClass('ac_sel');
		        	
		        	obj.unbind('focusout');
		        	
		        });
		        
		        $('#'+objid+'ddlist').mouseleave(function() {

					obj.focusout(function() {
						
						$('#'+objid+'ddlist').remove();
						
					});
		        	
		        });
		        
		        $('#'+objid+'ddlist div[class!=""]').click(function() {
		        	
		        	obj.val(defaults.select($(this).first().text(),cache[obj.val()][$(this).index()],obj,$(this)));
				
		        	$('#'+objid+'ddlist').remove();
					
				});
		        
		        obj.css('background-image','url()');
		        
			}
			
			obj.css('background-repeat','no-repeat');
			
			obj.css('background-position',(obj.innerWidth() - defaults.loadingimage.width) + 'px '+(obj.innerHeight() - defaults.loadingimage.height)+'px');

			obj.attr('autocomplete','off');

			obj.focusout(function() {
				
				$('#'+objid+'ddlist').remove();
				
			});
			
			obj.keyup(function(event) {
				
				function select() {
				
					obj.unbind('focusout');
					
					$('#'+objid+'ddlist div[class!=""]').removeClass('ac_sel');
					
					$('#'+objid+'ddlist div[class!=""]:eq('+selindex+')').addClass('ac_sel');

					$('#'+objid+'ddlist div[class!=""]:eq('+selindex+') a').focus(function() {
	
						$('#'+objid+'ddlist').scrollTop(cache[obj.val()][selindex].__top);
					
					});
					
					$('#'+objid+'ddlist div[class!=""]:eq('+selindex+') a').focus();
					
					obj.focus();
					
					obj.focusout(function() {
						
						$('#'+objid+'ddlist').remove();
						
					});

				}
				
				if($('#'+objid+'ddlist div[class!=""]').length>0) {
				
					var selindex = -1;
					
			        jQuery.each($('#'+objid+'ddlist div[class!=""]'), function(i, val) {
			        	
			        	if($(this).hasClass('ac_sel')) {
			        	
			        		selindex = i;
			        		
			        	}
			        	
			        });
			        
			        if(event.keyCode==40) { // down
			        	
						if(selindex==$('#'+objid+'ddlist div[class!=""]').length-1) {
							
							selindex = -1;
							
						}
						
						selindex++;
						
						select();

						return;
						
					}
			        
					if(event.keyCode==38) { // up
						
						if(selindex<=0) {
						
							selindex = $('#'+objid+'ddlist div[class!=""]').length;
							
						}
					
						selindex--;
						
						select();
						
						return;
						
					}
					
					if(event.keyCode==13) { // enter
						
						obj.val(defaults.select($('#'+objid+'ddlist div[class!=""]:eq('+selindex+')').first().text(),cache[obj.val()][selindex],obj,$('#'+objid+'ddlist div[class!=""]:eq('+selindex+')')));
						
						$('#'+objid+'ddlist').remove();
						return;
						
					}
					
				}
				
				$('#'+objid+'ddlist').remove();
				
				if(obj.val().length>=defaults.letters) {
					
					if(thread != null) {
						
						clearTimeout(thread);
						
					}
					
					obj.css('background-image','url('+defaults.loadingimage.url+')');
					
					thread = setTimeout(function() {

						if( (defaults.cache == true) && (cache[obj.val()]) ) {
							
							dropdown(cache[obj.val()]);
							
						} else {
							
							if(defaults.url != null) {
							
								$.ajax({
									
									type: 'POST',
									async: false,
									timeout: 5000,
									data: 'search=' + encodeURIComponent(obj.val()) + '&limit=' + defaults.limit,
									dataType: 'json',
									url: defaults.url,
									
									error: function(xhr) {

										// doh !!!
										alert(xhr.responseText); //debug
										obj.css('background-image','url()');
				
									},
									
									success: function(result) {
										
										if(result) {
										
											cache[obj.val()] = result; // edit here
											dropdown(result); // edit here
											
										}
										
									}
									
								});
								
							} else {
								
								if(defaults.arraystring.length == 0) {
								
									defaults.arraystring = defaults.array.toString();
									
								}
								
								var regex = new RegExp("[^ \f\n\r\t\v,;\.?!'\"`´“]*" + obj.val() + "[^ \f\n\r\t\v,;\.?!'\"`´“]*","gi");
								var result = defaults.arraystring.match(regex);
								
								var words = new Array();
								
								if(result) {
								
									for (var i = 0; i < result.length; ++i) {
										
										words[i] = result[i];
										 
									}
									 
									words.sort();
									
									words = jQuery.unique(words);
									
								}
							
								cache[obj.val()] = words;
								dropdown(words);
								
							}
							
						}
						
					}, defaults.delay);	
					
				} else {
				
					obj.css('background-image','url()');
					
				}

			});
			
		});
		
	};
	
})(jQuery);
