/* Copyright (c) 2008 Kean Loong Tan http://www.gimiti.com/kltan
 * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * Copyright notice and license must remain intact for legal use
 * autoComplete
 * Version: 1.0 (May 26, 2008)
 * Requires: jQuery 1.2.6+
 *
 * Modified by Mark Yang in 18-5-2011
 */

//	A global variable that is used to count how many time the IE6 "select" object has been set hidden
//	Note that this variable may be defined more than one time by other JS plugins
var ie6HiddenCounter = 0;

(function($) {
		  
	$.fn.autoComplete = function(options) {
		// merge users option with default options
		var opts = $.extend({}, $.fn.autoComplete.defaults, options);		
		var myId = $(this).attr("id");
		
		var iniVal = $.trim($(this).val());
		var textBox = $(this).find("input");
		var textBoxRoot = $(this);
		var jC = "#" + $(this).attr("id") + "Container";
		var jH = jC + " .autoCompleteHover";
		var jsH = "autoCompleteHover";
		var closeTimeout = 0;
		var startTimeout = 0;
		var count = 0;
				
		$(textBox).addClass('autoCompleteSearchBox');
		$("body").append('<div id="' + myId + 'Container"></div>');
		$(jC).addClass('autoCompleteContainer').hide();
		$(textBox).attr('autocomplete', 'off');
		
		//////////////////////////////////////////////////////////////
		//	Key down event handler
		$(textBox).bind("keydown", function(e){
			if (e.keyCode == 40 || e.keyCode == 38) {
				//	Block up and down in text field
				return false;
			}
			if (e.keyCode == 13) {
				return false;
			}
			return true;
		});
		
		//////////////////////////////////////////////////////////////
		//	Key up event handler
		$(textBox).bind("keyup", function(e){
			
			textValue = $.trim(textBox.val());
			if (textValue.length >= opts.minchar && $.trim(textValue)!=opts.searchTerms) {
				var offSet = $(textBoxRoot).offset();
				
				//////////////////////////////////////////////////////////////////////////
				// check if new query detected
				//////////////////////////////////////////////////////////////////////////
				if (textValue != iniVal){
					
					// optimize server performance by loading at intervals
					clearTimeout(startTimeout);		// if have previous, remove it
					startTimeout = setTimeout(function () {
						
						if (textValue != $.trim(textBox.val()))
							return;		// check again if the text value is changed or not
						
						if (opts.width != "")
							containerWidth = opts.width;
						else	
							containerWidth = $(textBoxRoot).outerWidth()-6;

						//	*** Special handling for IE6 to hide the selection box
						if (jQuery.browser.msie && parseInt(jQuery.browser.version) == 6) {
							if (!ie6HiddenCounter)
								$("select").css({ visibility: "hidden" });
							ie6HiddenCounter ++;
							//alert(ie6HiddenCounter);
						}

						$(jC).css({
							position: "absolute",
							top: offSet.top + $(textBoxRoot).outerHeight() + "px",
							left: offSet.left,
							width: containerWidth + "px",
							opacity: opts.opacity,
							zIndex: opts.zindex
						}).show();
						
						iniVal = textValue;
						if ($(".autoCompleteLoading").length==0)
							$('<div class="autoCompleteLoading"><img src="'+opts.loadingImg+'" align="bottom" /> '+ opts.loadingText+'</div>').prependTo(jC);
						
						$(".autoCompleteLoading").show();
						$(jC).find('ul').remove();

						setTimeoutToClose();
						$.ajax({
							type: opts.type,
							url: opts.url + "/" + encodeURI(iniVal) + "/" + opts.bDistinct,
							success: function(msg){
								$(jC).find('ul').remove();
								$(jC).append(msg);
								
								if (!$(jC + " ul li").hasClass("notMatch")) {
									$(jC + " ul li").bind("mouseover", function(){
										setTimeoutToClose();		
										$(jH).removeClass(jsH);
										$(this).addClass(jsH);
										if (opts.autoChange)
											textBox.val($(jH).text());
									});
									$(jC + " ul li").click(function(){
										$(this).addClass(jsH);
										textBox.val($(this).attr('shopName'));
										opts.selectCallback($(this));
									});
									$(jC + " ul li:last-child").addClass("last");
								}	
								$(".autoCompleteLoading").hide();
							}
						});
						
					}, opts.delay);
					
				}
				

				//////////////////////////////////////////////////////////////////////////
				// Handle Keys if is show
				//////////////////////////////////////////////////////////////////////////
				if ($(jC).is(":visible")) {
				
					// if escape key
					if (e.keyCode == 27) {
						hideJC();
					}
					
					// if enter key
					else if (e.keyCode == 13 ) {
						if ($(jH).length == 1) {
							textBox.val($(jH).attr('shopName'));
							opts.selectCallback($(jH));
						}
						hideJC();
						iniVal = $.trim(textBox.val());
					}
					
					// if down arrow
					else if (e.keyCode == 40) {
						// if any suggestion is highlighted
						if ($(jH).length == 1) {
							if (!$(jH).next().length == 0) {
								$(jH).next().addClass(jsH);
								$(".autoCompleteHover:eq(0)").removeClass(jsH);
								if (opts.autoChange)
									textBox.val($(jH).text());
							}
						}
						else {
							$(jC + " ul li:first-child").addClass(jsH);
							if (opts.autoChange)
								textBox.val($(jH).text());
						}
						
					}
					
					// if up arrow
					else if (e.keyCode == 38) {
						// if any suggestion is highlighted
						if ($(jH).length == 1 ) {
							if (!$(jH).prev().length == 0) {
								$(jH).prev().addClass(jsH);
								$(".autoCompleteHover:eq(1)").removeClass(jsH);
								if (opts.autoChange)
									textBox.val($(jH).text());
							}
							// if is first child
							else {
								$(jH).removeClass(jsH);
								textBox.val(iniVal);
							}
						}
					}
				}
				else {
					//	Handle key not showing
					
					//	if enter key
					if (e.keyCode == 13 ) {
						opts.enterKeyCallback();
					}
				}
				
				setTimeoutToClose();
			}
			else {
				// if text is too short do nothing and hide everything
				clearTimeout(closeTimeout);
				$(jH).removeClass(jsH);
				hideJC();
			}
			
			// no bubbling, click is binded to textBox to prevent document bind from firing
			return false;
		});
		
		//////////////////////////////////////////////////////////////
		//	Bind change event of the textbox
		$(textBoxRoot).bind("change", function(e){
			if ($.trim($(textBox).val())=="" || $.trim($(textBox).val())==opts.searchTerms) {
				$(textBox).val(opts.searchTerms);
				$(textBox).removeClass("autoCompleteNormal");
			}
			else
				$(textBox).addClass("autoCompleteNormal");
		});	
		
		//////////////////////////////////////////////////////////////
		//	Handle default search terms
		if (opts.searchTerms != "") {
			if ($.trim(opts.defaultText) == "")
				textBox.val(opts.searchTerms);
			else {
				textBox.val(opts.defaultText);
				textBox.addClass("autoCompleteNormal");
			}	

			$(textBox).focus(function(){
				if ($.trim($(this).val()) == opts.searchTerms)
					$(this).val('');
				$(this).addClass("autoCompleteNormal");
			});
			
			$(textBox).blur(function(){
				if ($.trim($(this).val()) == "") {
					$(this).val(opts.searchTerms);
					$(this).removeClass("autoCompleteNormal");
				}
			});
		}
		else
			textBox.val(opts.defaultText);
		
		//////////////////////////////////////////////////////////////
		// why no use $(this).blur ?, because autoComplete box is hidden before click fires so this is the only way to do it
		// alternate way is to say that text blur will fire before$(jC + " ul li") click.
		$(document).bind("click", function(){
			hideJC();
			iniVal = textBox.val();
		});
		
		//////////////////////////////////////////////////////////////
		//	Timeout to close the dialog
		function setTimeoutToClose() {
			clearTimeout(closeTimeout);	// cancel previous timeout if any
			if (opts.timeoutToHide > 0)
				closeTimeout = setTimeout(function () {
					hideJC();
				}, opts.timeoutToHide);
		}				

		//////////////////////////////////////////////////////////////
		//	hide the container, something may need to do
		function hideJC() {
			if ($(jC).is(":visible")) {
				$(jC).hide();

				//	*** Special handling for IE6 to restore the selection box
				if (jQuery.browser.msie && parseInt(jQuery.browser.version) == 6){
					if (ie6HiddenCounter == 1)
						$("select").css({ visibility: "visible" });
					if (ie6HiddenCounter > 0)
						ie6HiddenCounter --;
					//alert(ie6HiddenCounter);
				}
			}
		}

	};
	
	$.fn.autoComplete.defaults = {
		minchar: 1,
		opacity: 1.0,
		zindex: 20000,
		width: "",
		delay: 200,
		loadingImg: 'ajax-loader.gif',
		loadingText: 'Loading...',
		autoChange: false,
		url: "",
		searchTerm: "",
		defaultText: "",
		type: "GET",
		timeoutToHide: 0,
		bDistinct: 1,
		enterKeyCallback: function(){},
		selectCallback: function(){}
	};

})(jQuery);
