/*
 * 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(){
    $jquery_1_5_2.fn.autoSuggest = function(data, options) {
	var defaults = { 
	    asHtmlID: false,
		initText: "", // SEB : ajout de la possibilité de setter un texte "libre"
		freeInputAllowed:true,// TRI : ajout d'un param pour autoriser au non la saisie libre
	    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,
	    showResultList: true,
	    start: function(){},
	    selectionClick: function(elem){},
	    selectionAdded: function(elem){},
	    selectionRemoved: function(elem){ elem.remove(); },
	    formatList: false, //callback function
	    beforeRetrieve: function(string){ return string; },
	    retrieveComplete: function(data){ return data; },
	    resultClick: function(data){},
	    resultsComplete: function(){},
	    showingResult: function(){},// callback apres affichage des résultats
	    closingResult: function(){}// callback apres fermeture des résultats
	};  
	var opts = $jquery_1_5_2.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
		    var x_id = "as-input-"+x;
		} else {
		    x = opts.asHtmlID;
		    var x_id = x;
		}
		opts.start.call(this);
		var input = $jquery_1_5_2(this);
		// SEB : modif pour maintient d'un texte "libre" + TRI : ajout d'une classe as-input-initial pour styles différentiés
		input.attr("autocomplete","off").addClass("as-input as-input-initial").attr("id",x_id).val(opts.initText != "" ? opts.initText : opts.startText);
		var input_focus = false;
		
		// Setup basic elements and render them to the DOM
		input.wrap('<ul class="as-selections" id="as-selections-'+x+'"></ul>').wrap('<li class="as-original" id="as-original-'+x+'"></li>');
		var selections_holder = $jquery_1_5_2("#as-selections-"+x);
		var org_li = $jquery_1_5_2("#as-original-"+x);				
		var results_holder = $jquery_1_5_2('<div class="as-results" id="as-results-'+x+'"></div>').hide();
		var results_ul =  $jquery_1_5_2('<ul class="as-list"></ul>');
		var values_input = $jquery_1_5_2('<input type="hidden" class="as-values" name="as_values_'+x+'" id="as-values-'+x+'" value="" />');
		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("");
		    var lastChar = prefill_value.substring(prefill_value.length-1);
		    if(lastChar != ","){ prefill_value = prefill_value+","; }
		    values_input.val(","+prefill_value);
		    // TRI : ajout de 2 classes : as-input-rempli & as-input-initial
		    $jquery_1_5_2("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);	

		var timeout = null;
		var prev = "";
		var totalSelections = 0;
		var tab_press = false;
		
		// Handle input field events
		input.focus(function(){
		    if($jquery_1_5_2(this).val() == opts.startText && values_input.val().replace(",","") == ""){
		    	$jquery_1_5_2(this).val("");
		    } else if(input_focus){
		    	$jquery_1_5_2("li.as-selection-item", selections_holder).removeClass("blur");
				if($jquery_1_5_2(this).val() != ""){
				    results_ul.css("width",selections_holder.outerWidth());
				    openResults();
				}
		    }
	    	// TRI : ajout de 2 classes : as-input-rempli & as-input-initial
		    $jquery_1_5_2(this).addClass("as-input-rempli").removeClass("as-input-initial");
		    input_focus = true;
		    return true;
		}).blur(function(){
		    if($jquery_1_5_2(this).val() == "" && values_input.val().replace(",","") == ""){
		    	//TRI: modification pour permettre l'affichage du starttext si on a supprimé les éléments 
		    	//de l'input(mm si il y avait un prefill) && prefill_value == ""){
		    	$jquery_1_5_2(this).val(opts.startText).addClass("as-input-initial").removeClass("as-input-rempli");
		    } else if(input_focus){
				$jquery_1_5_2("li.as-selection-item", selections_holder).addClass("blur").removeClass("selected");
				closeResults();
				// TRI : si saisie libre interdite, on vire le contenu du champs
				if(!opts.freeInputAllowed && $jquery_1_5_2(this).css("display") != "none"){
					$jquery_1_5_2(this).attr("value","");
					$jquery_1_5_2(this).val(opts.startText).addClass("as-input-initial").removeClass("as-input-rempli");
				}
		    }
		}).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+",",","));
				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){
			    closeResults();
			    prev = "";
			}
			if($jquery_1_5_2(":visible",results_holder).length > 0){
			    if (timeout){ clearTimeout(timeout); }
			    timeout = setTimeout(function(){ keyChange(); }, opts.keyDelay);
			}
			break;
/*// TRI : suppression du comportement sur la touche 'tab'
  		    case 9: case 188:  // tab or comma
			tab_press = true;
			var i_input = input.val().replace(/(,)/g, "");
			if(i_input != "" && values_input.val().search(","+i_input+",") < 0 && i_input.length >= opts.minChars){	
			    e.preventDefault();
			    var n_data = {};
			    n_data[opts.selectedItemProp] = i_input;
			    n_data[opts.selectedValuesProp] = i_input;																				
			    var lis = $jquery_1_5_2("li", selections_holder).length;
			    add_selected_item(n_data, "00"+(lis+1));
			    input.val("");
			}
*/		    case 13: // return
			tab_press = false;
			var active = $jquery_1_5_2("li.active:first", results_holder);
			if(active.length > 0){
			    active.click();
			    closeResults();
			}
			if(opts.neverSubmit || active.length > 0){
			    e.preventDefault();
			}
			break;
		    default:
			if(opts.showResultList){
			    if(opts.selectionLimit && $jquery_1_5_2("li.as-selection-item", selections_holder).length >= opts.selectionLimit){
				results_ul.html('<li class="as-message">'+opts.limitText+'</li>');
				openResults();
			    } 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 closeResults(); }
		    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 = "&rows="+encodeURIComponent(opts.retrieveLimit);
			    }
			    if(opts.beforeRetrieve){
				string = opts.beforeRetrieve.call(this, string);
			    }
			    // TRI : modification pour gestion d'erreurs
		        $jquery_1_5_2.jsonp({
		        	url: req_string+"?"+opts.queryParam+"="+encodeURIComponent(string)+"*"+limit+opts.extraParams,
		        	error: function (){http500()},
		        	success: function(data){
						d_count = 0;
						var new_data = opts.retrieveComplete.call(this, data, opts.lang, true);
						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 {
			selections_holder.removeClass("loading");
			closeResults();
		    }
		}
		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 = true;
			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 = $jquery_1_5_2.trim(names[y]);
				str = str+data[num][name]+" ";
			    }
			}
			if(str){
			    if (!opts.matchCase){ str = str.toLowerCase(); }				
			    if(str.search(query) != -1 && values_input.val().search(","+data[num][opts.selectedValuesProp]+",") == -1){
				forward = true;
			    }
			}
			if(forward){
			    var formatted = $jquery_1_5_2('<li class="as-result-item" id="as-result-item-'+num+'"></li>').click(function(){
				var raw_data = $jquery_1_5_2(this).data("data");
				var number = raw_data.num;
				if($jquery_1_5_2("#as-selection-"+number, selections_holder).length <= 0 && !tab_press){
				    var data = raw_data.attributes;
				    input.val("").focus();
				    prev = "";
				    add_selected_item(data, number);
				    opts.resultClick.call(this, raw_data);
				    closeResults();
				}
				tab_press = false;
			    }).mousedown(function(){ input_focus = false; }).mouseover(function(){
				$jquery_1_5_2("li", results_ul).removeClass("active");
				$jquery_1_5_2(this).addClass("active");
			    }).data("data",{attributes: data[num], num: num_count});
			    var this_data = $jquery_1_5_2.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());
		    openResults();
		    opts.resultsComplete.call(this);
		}
		
		function add_selected_item(data, num){
			// TRI : correction bug : la 1ere ville selectionnée puis supprimée est gardée dans les ids
			if(values_input.val() == ""){
				values_input.val(",");
			}
		    values_input.val(values_input.val()+data[opts.selectedValuesProp]+",");
		    var item = $jquery_1_5_2('<li class="as-selection-item" id="as-selection-'+num+'"></li>').click(function(){
			opts.selectionClick.call(this, $jquery_1_5_2(this));
			selections_holder.children().removeClass("selected");
			$jquery_1_5_2(this).addClass("selected");
		    }).mousedown(function(){ input_focus = false; });
		    var close = $jquery_1_5_2('<a class="as-close">&times;</a>').click(function(){
			values_input.val(values_input.val().replace(","+data[opts.selectedValuesProp]+",",","));
			opts.selectionRemoved.call(this, item);
			input_focus = true;
			// TRI : modification pour réafficher le champs de saisie sur la suppression d'un élément
			org_li.show();
			if($jquery_1_5_2("li.as-selection-item",selections_holder).length == 0){
				input.focus();
				// suppression de la liste de résulats déjà en cache
				results_holder.html(results_ul.html("")).hide();
			}
			return false;
		    });
		    org_li.before(item.html(data[opts.selectedItemProp]).prepend(close));
		    // TRI : modification pour cacher le champs de saisie si plus de saisie disponible
		    if(opts.selectionLimit <= $jquery_1_5_2("li.as-selection-item",selections_holder).length){
		    	org_li.hide();
			}
		    // TRI : envoi a selection added de deux éléments : le li ajouté dans le champs de recherche et le doc lié
		    opts.selectionAdded.call(this, org_li.prev(), data);
		}
		
		function moveSelection(direction){
		    if($jquery_1_5_2(":visible",results_holder).length > 0){
			var lis = $jquery_1_5_2("li", results_holder);
			if(direction == "down"){
			    var start = lis.eq(0);
			} else {
			    var start = lis.filter(":last");
			}					
			var active = $jquery_1_5_2("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");
		    }
		}
		
		// fonction permettant d'exécuter un callback sur l'ouverture des results 
		function openResults(){
			results_holder.show();
			opts.showingResult.call(this);
		}
		// fonction permettant d'exécuter un callback sur la fermeture des results 
		function closeResults(){
			results_holder.hide();
			opts.closingResult.call(this);
		}
		
	    });
	}
    }
})($jquery_1_5_2);
