 /*
 * AutoSuggest
 * Copyright 2009-2010 Drew Wilson
 * www.drewwilson.com
 * code.drewwilson.com/entry/autosuggest-jquery-plugin
 *
 * Version 1.4   -   Updated: Mar. 23, 2010
 *
 * This Plug-In will auto-complete or auto-suggest completed search queries
 * for you as you type. You can add multiple selections and remove them on
 * the fly. It supports keybord navigation (UP + DOWN + RETURN), as well
 * as multiple AutoSuggest fields on the same page.
 *
 * Inspied by the Autocomplete plugin by: J?rn Zaefferer
 * and the Facelist plugin by: Ian Tearle (iantearle.com)
 *
 * This AutoSuggest jQuery plug-in is dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 */

(function($){
	$.fn.autoSuggest = function(data, options) {
		var defaults = {
			startText: "", //Enter Name Here
			emptyText: "No Results Found",
			preFill: {},
			limitText: "No More Selections Are Allowed",
			selectedItemProp: "keyword", //value //name of object property
			selectedValuesProp: "keyword", //value //name of object property
			searchObjProps: "keyword", //value //comma separated list of object property names
			queryParam: "keywords", // q
			retrieveLimit: 10, //false //number for 'limit' param on ajax request
			extraParams: "",
			matchCase: false,
			matchGlobal: false,
			minChars: 1,
			keyDelay: 50,
			resultsMargin: "0",
			resultsHighlight: true,
			neverSubmit: false,
			selectionLimit: false,
			showResultList: true,
			start: function(){},
			wrapStyle: "",
			selectionClick: function(elem){},
			selectionAdded: function(elem){},
			selectionRemoved: function(elem){ elem.remove(); },
			beforeRetrieve: function(string){ return string; },
			retrieveComplete: function(data){ return data; },
			resultClick: function(data){},
			formatList: function(this_data, formatted) {
				return formatted.html("<span style='float: left'>"+this_data["keyword"]+"</span><span style='font-size: 11px; color: #1f83cf; float: right'>"+this_data["cntString"]+"결과</span>");
			},
			resultsComplete: function(results_holder) {
				$(results_holder).prepend("<p>검색어 추천</p>");
			}
	  	};  
	 	var opts = $.extend(defaults, options);	
		var d_type = "object";
		var d_count = 0;
		var lastKeyPressCode = 0;
		var isSubmit = false;
		
		if(typeof data == "string") {
			d_type = "string";
			var req_string = data;
		} else {
			var org_data = data;
			for (k in data) if (data.hasOwnProperty(k)) d_count++;
		}
		
		if((d_type == "object" && d_count > 0) || d_type == "string"){
			return this.each(function(x){
				var input = $(this);
				var input_focus = false;
				
				opts.start.call(this);
				input.attr("autocomplete","off").addClass("as-input");
				if (opts.startText) input.val(opts.startText);
				
				// Setup basic elements and render them to the DOM
				input.wrap('<div style="' + opts.wrapStyle + '"></div>').wrap('<ul class="as-selections" id="as-selections-'+x+'"></ul>').wrap('<li class="as-original" id="as-original-'+x+'"></li>');
				var selections_holder = $("#as-selections-"+x);
				var org_li = $("#as-original-"+x);
				var results_holder = $('<div class="as-results" id="as-results-'+x+'"></div>').hide();
				var results_ul =  $('<ul class="as-list"></ul>');
				var values_input = "";
				var prefill_value = "";
				
				results_ul.css({"width": selections_holder.outerWidth()+opts.browserGap});
				results_holder.css({"margin": opts.resultsMargin});
				
				if(typeof opts.preFill == "string"){
					var vals = opts.preFill.split(",");	
					for(var i=0; i < vals.length; i++){
						var v_data = {};
						v_data[opts.selectedValuesProp] = vals[i];
						if(vals[i] != ""){
							add_selected_item(v_data, "000"+i);
						}		
					}
					prefill_value = opts.preFill;
				} else {
					prefill_value = "";
					var prefill_count = 0;
					for (k in opts.preFill) if (opts.preFill.hasOwnProperty(k)) prefill_count++;
					if(prefill_count > 0){
						for(var i=0; i < prefill_count; i++){
							var new_v = opts.preFill[i][opts.selectedValuesProp];
							if(new_v == undefined){ new_v = ""; }
							prefill_value = prefill_value+new_v+",";
							if(new_v != ""){
								add_selected_item(opts.preFill[i], "000"+i);
							}
						}
					}
				}
				
				if(prefill_value != ""){
					input.val("");
					var lastChar = prefill_value.substring(prefill_value.length-1);
					if(lastChar != ","){ prefill_value = prefill_value+","; }
					values_input = ","+prefill_value;
					$("li.as-selection-item", selections_holder).addClass("blur").removeClass("selected");
				}
				
				selections_holder.click(function(){
					input_focus = true;
					input.focus();
				}).mousedown(function(){ input_focus = false; }).after(results_holder);

				var timeout = null;
				var prev = "";
				var totalSelections = 0;
				var tab_press = false;
				
				// Handle input field events
				input.focus(function(){
					if($(this).val() == opts.startText && values_input == ""){
						$(this).val("");
					} else if(input_focus){
						$("li.as-selection-item", selections_holder).removeClass("blur");
						if($(this).val() != ""){
							if ($("li:first", results_holder).text() == opts.emptyText) {
								results_holder.hide();
							} else {
								if (input.val() != values_input) {
									if (!isSubmit) keyChange();
								} else {
									results_holder.show();
								}
							}
						}
					}
					input_focus = true;
					return true;
				}).blur(function(){
					if($(this).val() == "" && values_input == "" && prefill_value == ""){
						if (opts.startText) $(this).val(opts.startText);
					} else if(input_focus){
						$("li.as-selection-item", selections_holder).addClass("blur").removeClass("selected");
						results_holder.hide();
					}				
				}).keydown(function(e) {
					// track last key pressed
					lastKeyPressCode = e.keyCode;
					first_focus = false;
					switch(e.keyCode) {
						case 37: // left
							break;
						case 39: // right
							break;
						case 38: // up
							e.preventDefault();
							moveSelection("up");
							break;
						case 40: // down
							e.preventDefault();
							moveSelection("down");
							break;
						case 8:  // delete
							if(input.val() == ""){
								var last = values_input.split(",");
								last = last[last.length - 2];
								selections_holder.children().not(org_li.prev()).removeClass("selected");
								if(org_li.prev().hasClass("selected")){
									values_input = values_input.val().replace(","+last+",",",");
									opts.selectionRemoved.call(this, org_li.prev());
								} else {
									opts.selectionClick.call(this, org_li.prev());
									org_li.prev().addClass("selected");
								}
							}
							if(input.val().length <= 1){
								results_holder.hide();
								 prev = "";
							}
							else {
								if (timeout){ clearTimeout(timeout); }
								timeout = setTimeout(function(){ keyChange(); }, opts.keyDelay);
							}
							break;
						case 13: // return
							tab_press = false;
							var active = $("li.active:first", results_holder);
							if(active.length > 0){
								active.click();
								results_holder.hide();
							}
							if(opts.neverSubmit || active.length > 0){
								e.preventDefault();
							}
							break;
						default:
							if(opts.showResultList){
								if(opts.selectionLimit && $("li.as-selection-item", selections_holder).length >= opts.selectionLimit){
									results_ul.html('<li class="as-message">'+opts.limitText+'</li>');
									if ($("li:first", results_holder).text() == opts.emptyText) {
										results_holder.hide();
									} else {
										results_holder.show();
									}
								} else {
									if (timeout){ clearTimeout(timeout); }
									timeout = setTimeout(function(){ keyChange(); }, opts.keyDelay);
								}
							}
							break;
					}
				});
				
				function keyChange() {
					// ignore if the following keys are pressed: [del] [shift] [capslock]
					if( lastKeyPressCode == 46 || (lastKeyPressCode > 8 && lastKeyPressCode < 32) ){ return results_holder.hide(); }
					var string = convertHangul(input.val().replace(/[\\]+|[\/]+/g,""));
					
					if (string == prev) return;
					prev = string;
					if (string.length >= opts.minChars) {
						if(d_type == "string"){
							var limit = "";
							if(opts.retrieveLimit){
								limit = "&limit="+encodeURIComponent(opts.retrieveLimit);
							}
							if(opts.beforeRetrieve){
								string = opts.beforeRetrieve.call(this, string);
							}
							string = $.trim(string);
							values_input = string;
							
							if (string.length > 0) {
								$.getJSON(req_string+"?"+opts.queryParam+"="+encodeURIComponent(string)+limit+opts.extraParams, function(data){ 
									d_count = 0;
									var new_data = opts.retrieveComplete.call(this, data);
									for (k in new_data) if (new_data.hasOwnProperty(k)) d_count++;
									processData(new_data, string);
								});
							}
						} else {
							if(opts.beforeRetrieve){
								string = opts.beforeRetrieve.call(this, string);
							}
							processData(org_data, string);
						}
					} else {
						results_holder.hide();
					}
				}
				
				var num_count = 0;
				function processData(data, query){
					if (!opts.matchCase){ query = query.toLowerCase(); }
					var matchCount = 0;
					results_holder.html(results_ul.html("")).hide();
					for(var i=0;i<d_count;i++){
						var num = i;
						num_count++;
						var forward = false;
						if(opts.searchObjProps == "value") {
							var str = data[num].value;
						} else {
							var str = "";
							var names = opts.searchObjProps.split(",");
							for(var y=0;y<names.length;y++){
								var name = $.trim(names[y]);
								str = str+data[num][name]+" ";
							}
						}
						if(str){
							if (!opts.matchCase){ str = str.toLowerCase(); }
								forward = true;
						}
						if(forward){
							var formatted = $('<li class="as-result-item" id="as-result-item-'+num+'"></li>').click(function(){
									var raw_data = $(this).data("data");
									var number = raw_data.num;
									if($("#as-selection-"+number, selections_holder).length <= 0 && !tab_press){
										var data = raw_data.attributes;
										prev = "";
										add_selected_item(data, number);
										opts.resultClick.call(this, raw_data);
										results_holder.hide();
									}
									tab_press = false;
								}).mousedown(function(){ input_focus = false; }).mouseover(function(){
									$("li", results_ul).removeClass("active");
									$(this).addClass("active");
								}).data("data",{attributes: data[num], num: num_count});
							var this_data = $.extend({},data[num]);
							var regx = new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + query + ")(?![^<>]*>)(?![^&;]+;)", ((opts.matchCase)? "" : "i") + ((opts.matchGlobal)? "g" : ""));
							
							if(opts.resultsHighlight){
								this_data[opts.selectedItemProp] = this_data[opts.selectedItemProp].replace(regx,"<em>$1</em>");
							}
							if(!opts.formatList){
								formatted = formatted.html(this_data[opts.selectedItemProp]);
							} else {
								formatted = opts.formatList.call(this, this_data, formatted);
							}
							results_ul.append(formatted);
							delete this_data;
							matchCount++;
							if(opts.retrieveLimit && opts.retrieveLimit == matchCount ){ break; }
						}
					}
					if(matchCount <= 0){
						results_ul.html('<li class="as-message">'+opts.emptyText+'</li>');
					}
					results_ul.css("width", selections_holder.outerWidth()+opts.browserGap);
					if ($("li:first", results_holder).text() == opts.emptyText || matchCount <= 0) {
						results_holder.hide();
					} else {
						results_holder.show();
						opts.resultsComplete.call(this, results_holder);
					}
				}
				
				function add_selected_item(data, num){
					isSubmit = true;
					input.val(data[opts.selectedValuesProp]);
					$("form[name='search']").submit();
				}
				
				function moveSelection(direction){
					if($(":visible",results_holder).length > 0){
						var lis = $("li", results_holder);
						if(direction == "down"){
							var start = lis.eq(0);
						} else {
							var start = lis.filter(":last");
						}
						var active = $("li.active:first", results_holder);
						if(active.length > 0){
							if(direction == "down"){
							start = active.next();
							} else {
								start = active.prev();
							}	
						}
						lis.removeClass("active");
						start.addClass("active");
						
						if (!$("li.active > span:first", results_holder).text()) {
							input.val(values_input);
						}
						else {
							if (timeout){ clearTimeout(timeout); }
							input.val($("li.active > span:first", results_holder).text());
							results_holder.show();
						}
					}
				}
				
				function convertHangul(str) {
					var initial = "rRseEfaqQtTdwWczxvg";
					var regInitial = "[" + initial + "]";
					var medial = {k:0,o:1,i:2,O:3,j:4,p:5,u:6,P:7,h:8,hk:9,ho:10,hl:11,y:12,n:13,nj:14,np:15,nl:16,b:17,m:18,ml:19,l:20}
					var regMedial = "hk|ho|hl|nj|np|nl|ml|k|o|i|O|j|p|u|P|h|y|n|b|m|l";
					var final = {"":0,r:1,R:2,rt:3,s:4,sw:5,sg:6,e:7,f:8,fr:9,fa:10,fq:11,ft:12,fx:13,fv:14,fg:15,a:16,q:17,qt:18,t:19,T:20,d:21,w:22,c:23,z:24,x:25,v:26,g:27}
					var regFinal = "rt|sw|sg|fr|fa|fq|ft|fx|fv|fg|qt|r|R|s|e|f|a|q|t|T|d|w|c|z|x|v|g|";
					
					var reg_exp = new RegExp("("+regInitial+")("+regMedial+")((?:"+regFinal+")(?=(?:"+regInitial+")(?:"+regMedial+"))|(?:"+regFinal+"))", "g");
					
					var regAlpha =/^[a-zA-Z]+$/;
					var regHangul =/^[가-힣]+$/;
					
					temp = str.replace(reg_exp, function replace(str, h, b, f) { return String.fromCharCode(initial.indexOf(h)*21*28 + medial[b]*28 + final[f] + 44032); });
					
					if(temp && regHangul.test(temp) && !regAlpha.test(temp)) {
						str = temp;
					}
					
					return str;
				}
			});
		}
	}
})(jQuery);
