 /*
 * AutoSuggest
 * Copyright 2009-2010 Drew Wilson
 * www.drewwilson.com
 * code.drewwilson.com/entry/autosuggest-jquery-plugin
 *
 * Version 1.3   -   Updated: Feb. 07, 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: Jrn 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 parseIntNaN(string) {
	
	var integer = parseInt(string);
	
	return (!isNaN(integer)) ? integer : 0;
	
}

$(function(){
    autoSuggestInput = {
        settings: {
            inputSelector: 'input.as-input',
            selectionsHolderSelector: 'ul.as-selections'
        },
        reset: function() {
            var inputSelector = this.settings.inputSelector;
            if (typeof($(inputSelector)) == 'undefined') {
                return false;
            }
            var notMyLiCount = 0;
            $(this.settings.selectionsHolderSelector).find('li').each(function(i, elm) {
                if ($(elm).find(inputSelector).length == 0) {
                    notMyLiCount++;
                }
            });
            if (notMyLiCount > 0) {
                $(inputSelector).val('');
            } else if(typeof(autoSuggestOptions) != 'undefined') {
                $(inputSelector).val(autoSuggestOptions.startText);
            }

            /*width = parseIntNaN($(inputSelector).css('min-width'));
            if (width > 0) {
                $(inputSelector).css('width', width + 'px');
            }*/

            this.setAutoWidth();
        },
        setAutoWidth: function() {
            var inputSelector = this.settings.inputSelector;
            
            if (($(inputSelector).length == 0) || ($(this.settings.selectionsHolderSelector).length == 0)) {
                return false;
            }

            //try {
                maxInputWidth = parseIntNaN($(this.settings.selectionsHolderSelector).width());
                if (maxInputWidth == 0) {
                    maxInputWidth = parseIntNaN($(this.settings.selectionsHolderSelector).css('min-width'));
                }
                maxInputWidth -= parseIntNaN($(this.settings.selectionsHolderSelector).css('padding-right'));
                maxInputWidth -= parseIntNaN($(this.settings.selectionsHolderSelector).css('padding-left'));
                if (!jQuery.browser.msie) {
                    maxInputWidth -= parseIntNaN($(inputSelector).css('margin-right'));
                    maxInputWidth -= parseIntNaN($(inputSelector).css('margin-left'));
                } else {
                    maxInputWidth -= 10;
                }
                maxInputWidth -= parseIntNaN($(inputSelector).css('border-right-width'));
                maxInputWidth -= parseIntNaN($(inputSelector).css('border-left-width'));

                maxInputWidth -= parseIntNaN($(inputSelector).css('padding-right'));
                maxInputWidth -= parseIntNaN($(inputSelector).css('padding-left'));

                lastLiPosRight = 0;
                lastLiLine = false;
                $lastLi = $(this.settings.selectionsHolderSelector).find('li:not(.as-original):last');
                if ($lastLi.length > 0) {
                    lastLiPosRight = $lastLi.get(0).offsetLeft + $lastLi.get(0).offsetWidth;
                    lastLiLine = parseIntNaN($lastLi.get(0).offsetTop / $lastLi.get(0).offsetHeight);
                }

                width = maxInputWidth - lastLiPosRight;
                min_width = parseIntNaN($(inputSelector).css('min-width'));
                max_width = parseIntNaN($(inputSelector).css('max-width'));
                if ((min_width > 0) && (min_width > width)) {
                    width = min_width;
                }
                if ((max_width > 0) && (width > max_width)) {
                    width = max_width;
                }
                
                $(inputSelector).css('width', width + 'px');

                //if the input isn't on same line as last li then set it's width to maximum
                inputLine = parseIntNaN($(inputSelector).parent().get(0).offsetTop / $(inputSelector).parent().get(0).offsetHeight);
                if ((lastLiLine !== false) && (inputLine > lastLiLine)) {
                    width = maxInputWidth;
                    if ((min_width > 0) && (min_width > width)) {
                        width = min_width;
                    }
                    if ((max_width > 0) && (width > max_width)) {
                        width = max_width;
                    }
                    $(inputSelector).css('width', width + 'px');
                }
            //} catch(e) {}
        }
    }
});

(function($){
	$.fn.autoSuggest = function(data, options) {
		var defaults = { 
			asHtmlID: false,
			startText: "Enter Name Here",
			emptyText: "No Results Found",
			preFill: {},
			limitText: "No More Selections Are Allowed",
			selectedItemProp: "value", //name of object property
			selectedValuesProp: "value", //name of object property
			searchObjProps: "value", //comma separated list of object property names
			queryParam: "q",
			retrieveLimit: false, //number for 'limit' param on ajax request
			extraParams: "",
			matchCase: false,
			minChars: 1,
			keyDelay: 400,
			resultsHighlight: true,
			neverSubmit: false,
			selectionLimit: false,
		  	start: function(){},
		  	selectionClick: function(elem){},
		  	formatList: false, //callback function
		  	retrieveComplete: function(data){return data;},
		  	resultClick: function(data){},
		  	resultsComplete: function(){}
	  	};  
	 	var opts = $.extend(defaults, options);
		
		var d_type = "object";
		var d_count = 0;
		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){
				if(!opts.asHtmlID){
					x = x+""+Math.floor(Math.random()*100); //this ensures there will be unique IDs on the page if autoSuggest() is called multiple times
				} else {
					x = opts.asHtmlID;
				}
				opts.start.call(this);
				var input = $(this);
				
				// Setup basic elements and render them to the DOM
				if ($('#as-selections-' + x).length > 0) {
					input.attr("autocomplete","off").addClass("as-input").attr("id","as-input-"+x);
					if (!($('.as-selection-item').length > 0)) {
						input.val(opts.startText);
					}
				} else {
					input.attr("autocomplete","off").addClass("as-input").attr("id","as-input-"+x).attr('name', 'locality').val(opts.startText);
					var input_focus = false;
					input.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;
				if ($('input.as-values').length > 0) {
					values_input = $('input.as-values');
				} else {
					values_input = $('<input type="hidden" class="as-values" name="as_values_'+x+'" id="as-values-'+x+'" disabled="disabled" />');
				}

				var prefill_value = "";
				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("");
					values_input.val(prefill_value);
					$("li.as-selection-item", selections_holder).addClass("blur").removeClass("selected");
				}
				input.after(values_input);
				selections_holder.click(function(){
					input_focus = true;
					input.focus();
				}).mousedown(function(){input_focus = false;}).after(results_holder);

                autoSuggestInput.setAutoWidth();

				var timeout = null;
				var prev = "";
				var totalSelections = 0;
				
				// Handle input field events
				input.focus(function(){
					if($(this).val() == opts.startText && values_input.val() == ""){
						$(this).val("");
					} else if(input_focus){
						$("li.as-selection-item", selections_holder).removeClass("blur");
						if($(this).val() != ""){
							results_ul.css("width",selections_holder.outerWidth());
							results_holder.show();
						}
					}
					input_focus = true;
					return true;
				}).blur(function(){
					if($(this).val() == "" && values_input.val() == "" && prefill_value == ""){
						$(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 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.val().split(",");
								last = last[last.length - 2];
								selections_holder.children().not(org_li.prev()).removeClass("selected");
								if(org_li.prev().hasClass("selected")){
									values_input.val(values_input.val().replace(last+",",""));
									org_li.prev().remove();
								} else {
									opts.selectionClick.call(this, org_li.prev());
									org_li.prev().addClass("selected");
								}
							}
							if(input.val().length == 1){
								results_holder.hide();
								prev = "";
							}
							if($(":visible",results_holder).length > 0){
								if (timeout){clearTimeout(timeout);}
								timeout = setTimeout(function(){keyChange();}, opts.keyDelay);
							}
                            autoSuggestInput.setAutoWidth();
							break;
						case 9:  // tab
						case 13: // return
							if (results_holder.is(':visible')) {
								var doNotSubmit = false;
								var active = $("li.active:first", results_holder);
								if(active.length > 0) {
									active.click();
									results_holder.hide();
								} else {
									$("li:first", results_holder).click();
									results_holder.hide();
									doNotSubmit = true;
								}
								if (opts.neverSubmit || active.length > 0 || doNotSubmit){
									try {
										e.preventDefault();
									} catch(err) {
										e.returnValue = false;
									}
								}
							}
							break;
						default:
							if(opts.selectionLimit && $("li.as-selection-item", selections_holder).length >= opts.selectionLimit){
								results_ul.html('<li class="as-message">'+opts.limitText+'</li>');
								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 = input.val().replace(/[\\]+|[\/]+/g,"");
					if (string == prev) return;
					prev = string;
					if (string.length >= opts.minChars) {
						selections_holder.addClass("loading");
						if(d_type == "string"){
							var limit = "";
							if(opts.retrieveLimit){
								limit = "&limit="+encodeURIComponent(opts.retrieveLimit);
							}
							$.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 {
							processData(org_data, string);
						}
					} else {
						selections_holder.removeClass("loading");
						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();}
							/* Do not filter any results */
							
							/* str.search(query) != -1 && */
							
							if(values_input.val().search(data[num][opts.selectedValuesProp] + ",") == -1) {
								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){
										var data = raw_data.attributes;
										input.val("").focus();
										prev = "";
										values_input.val(values_input.val()+data[opts.selectedValuesProp]+",");
										add_selected_item(data, number);
										opts.resultClick.call(this, raw_data);
										results_holder.hide();
									}
								}).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]);
							if (!opts.matchCase){ 
								var regx = new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + query + ")(?![^<>]*>)(?![^&;]+;)", "gi");
							} else {
								var regx = new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + query + ")(?![^<>]*>)(?![^&;]+;)", "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;}
						}
					}
					selections_holder.removeClass("loading");
					if(matchCount <= 0){
						results_ul.html('<li class="as-message">'+opts.emptyText+'</li>');
					}
					results_ul.css("width", selections_holder.outerWidth());
					if (jQuery.browser.msie){
						results_holder.append('<iframe></iframe>');
					}
					results_holder.show();
					if (jQuery.browser.msie){
						results_holder.find('iframe').css({"width": results_ul.width(), "height": results_ul.height()});
					}
					opts.resultsComplete.call(this);
				}
				
				function add_selected_item(data, num){
					
					var typeIdentifier = 'city';
					
					type = parseInt(data['type']);
					
					typeIdentifierArr = new Array();
                    typeIdentifierArr[1] = 'region';
                    typeIdentifierArr[2] = 'district';
                    typeIdentifierArr[3] = 'city';
                    typeIdentifierArr[4] = 'city_borough';

                    if (typeof(typeIdentifierArr[type]) != 'undefined') {
                        typeIdentifier = typeIdentifierArr[type];
                    }

					var item = $('<li class="as-selection-item" id="as-selection-' + data['value'] +'"></li>').click(function(){
							opts.selectionClick.call(this, $(this));
							selections_holder.children().removeClass("selected");
							$(this).addClass("selected");
                            autoSuggestInput.setAutoWidth();
						}).mousedown(function(){input_focus = false;});
					var close = $('<a class="as-close">&times;</a>').click(function(){
							values_input.val(values_input.val().replace(data[opts.selectedValuesProp]+",",""));
							item.remove();
							input_focus = true;
							input.focus();
                            autoSuggestInput.setAutoWidth();
							return false;
						});
					
					/*
					var inpt = $('<input type="hidden" />').addClass(typeIdentifier)
                    .attr('id', typeIdentifier + data[typeIdentifier])
                    .attr('name', typeIdentifier + '[]')
                    .val(data[typeIdentifier]);

                    org_li.before(item.html(data[opts.selectedItemProp]).append(inpt).append(close));*/
                    org_li.before(item.html(data[opts.selectedItemProp]).append(close));
    
                    //close all parent locations selected: when city is currently selected, it's district is removed
                    $(selections_holder).find('input.' + typeIdentifier + '[value="' + data[typeIdentifier] + '"]').parent().find('a.as-close').trigger('click');
                    tmpType = 1;
                    while (tmpType < typeIdentifierArr.length) {
                        if ((typeof(typeIdentifierArr[tmpType]) != 'undefined') && (typeof(data[typeIdentifierArr[tmpType]]) != 'undefined') && (data[typeIdentifierArr[tmpType]] > 0)) {
                            typeIdentifier = typeIdentifierArr[tmpType];
                            
                            var inpt = $('<input type="hidden" />');
    
                            inpt.addClass(typeIdentifier)
                               .attr('name', typeIdentifier + '[]')
                               .attr('disabled', true)
                               .val(data[typeIdentifier]);
                             
                            if ((typeof(typeIdentifierArr[tmpType+1]) == 'undefined') || (typeof(data[typeIdentifierArr[tmpType+1]]) == 'undefined') || !(data[typeIdentifierArr[tmpType+1]] > 0)) {
                                
                                inpt.attr('id', typeIdentifier + data[typeIdentifier]).removeAttr('disabled');
                                tmpType2 = tmpType;
                                while (tmpType2 > 0) {
                                    typeIdentifier = typeIdentifierArr[tmpType2];
                                    $(selections_holder).find('input.' + typeIdentifier + '[value="' + data[typeIdentifier] + '"]:not(:disabled)').parent().find('a.as-close').trigger('click');
                                    tmpType2--;
                                }
                            }
                             
                            inpt.appendTo(item);
                        }
                        tmpType++;
                    }
                    autoSuggestInput.setAutoWidth();
				}
				
				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");
					}
				}


			});
		}
	}
})(jQuery);
