/**
 * SpexLive AutoComplete JavaScript Library.
 * This file binds events required for AutoComplete feature and contains methods used in Autocomplete.
 * 
 * @version 1.0.0
 * @author: Waqas Memon (wmemon@etilizepak.com)
 * 			Etilize Pvt. Ltd. (A GFK Product Data Company) 
 */



function SpexLiveAutoComplete(){
	/**
	 * Handle $ sign conflict between jQuery & prototype.
	 */
	this.JQ = jQuery.noConflict();
			
	this.autoCompleteSuggestionsBox = "suggestionsBox";
	this.autoSuggestionsList = "autoSuggestionsList";

	spxautocompleteconfig.autoCompleteField = "#"+spxautocompleteconfig.autoCompleteField;
	
	//on DOM ready
	this.JQ(document).ready(function() {
		
		/**
		 * Locale is the language and country code the website is working with. This can be hard-coded as it is, or you can select value of 
		 * any hidden field and/or html select/combo, etc. 
		 * 
		 ******************************************************************************************************************************/
		// TODO: CHANGE FOLLOWING CODE, IF AND ONLY IF YOU WANT TO CHANGE DEFAULT IMPLEMENTATION OF HANDLING MULTIPLE LOCALES..
		if(spxautocomplete.JQ("#"+spxautocompleteconfig.localeField) && spxautocomplete.JQ("#"+spxautocompleteconfig.localeField).val() !==""){
			//This will set locale to the value of the html input/select field
			spxautocompleteconfig.LOCALE = spxautocomplete.JQ("#"+spxautocompleteconfig.localeField).val();
			
			//This binds an onchange event to html input/select field to change the value of the locale on the run. 
			spxautocomplete.JQ("#"+spxautocompleteconfig.localeField).change(function(){
				spxautocompleteconfig.LOCALE = spxautocomplete.JQ("#"+spxautocompleteconfig.localeField).val();
			});
		}		
		
		if(!spxautocompleteconfig.LOCALE || spxautocompleteconfig.LOCALE == ""){
			//TODO: If you store selected site locale in any other way then input hidden field, please implement it here by yourself.
			spxautocompleteconfig.LOCALE = spxautocompleteconfig.defaultLocale;
		}			
		/******************************************************************************************************************************/
		
		
		//This will add ignoreme text field in DOM which will be used for crawler detection.
		spxautocomplete.prototype.blockCrawling();
		
		this.currentSelection = -1;
		this.currentValue = '';
		this.oldValue = '';
		//added timeout to handle keypress and hold problem, also limiting requests when user wants to type words.
		var hitTimeOut = null;
		spxautocomplete.JQ(spxautocompleteconfig.autoCompleteField).keyup(function(e) {
			//pageUp, pgDown, insert, home, end, arrow keys, 
			if(!(e.which > 32 &&  e.which < 46)) {
				if(hitTimeOut)
		            clearTimeout(hitTimeOut);
		
				//timeout found after a little research, appears to derive from Neilsen as 100ms
				//References: http://stackoverflow.com/questions/4255027/what-is-a-good-timeout-for-autocomplete-results
				hitTimeOut = setTimeout(function(){spxautocomplete.prototype.bindKeypressEvent(e);}, 150);
				
			}
		});


		spxautocomplete.prototype.addListBoxToDOM();
		
		spxautocomplete.JQ(spxautocompleteconfig.autoCompleteField).blur(function(e) {
			spxautocomplete.prototype.fill(spxautocomplete.JQ(spxautocompleteconfig.autoCompleteField).val());
		});

		spxautocomplete.prototype.bindListEvent();		
	});
	
}
var spxautocomplete = new SpexLiveAutoComplete(); 


spxautocomplete.prototype = {

		/**
		 * This method will block crawler traffic on text field by adding a dummy text field in form to fool the crawler. 
		 */
		blockCrawling: function(){
			//TODO: insert after parent may cause issues when input element's immediate parent is form.
			spxautocomplete.JQ('<input type="text" id="ignoreme" style=\"display:none;\"/>').insertAfter(spxautocomplete.JQ(spxautocompleteconfig.autoCompleteField).parent());
	
		},
		
		/**
		 * This method checks if the DOM has been loaded and if its ready, it binds events with input text field<br>
		 * and LI list items for keyboard and mouse navigation.  
		 */	

		addListBoxToDOM: function (){
			spxautocomplete.JQ('<div class="autocomplete_container"><div class="'+spxautocompleteconfig.suggestionBoxCSSClass+'" id="'+spxautocomplete.autoCompleteSuggestionsBox+'" style="display: none;" >'
					+'<div class="'+spxautocompleteconfig.suggestionListCSSClass+'" id="'+spxautocomplete.autoSuggestionsList+'"></div>'
					+ '</div></div>').insertAfter(spxautocompleteconfig.autoCompleteField);
		},

		/**
		 * Autocomplete event for input field,
		 */ 
		bindKeypressEvent: function (e){
			if(e.which ==13 || e.which ==27){ //Enter or escape
				spxautocomplete.prototype.fill(spxautocomplete.JQ(spxautocompleteconfig.autoCompleteField).val());
				
			}else{
				var newValue = spxautocomplete.JQ(spxautocompleteconfig.autoCompleteField).val();
				if(spxautocomplete.oldValue !== newValue){
					spxautocomplete.oldValue = spxautocomplete.JQ(spxautocompleteconfig.autoCompleteField).val();
						spxautocomplete.prototype.lookup(spxautocomplete.oldValue);
				}				
			}
		},
		
		/**
		 * Navigation events for List of suggestions
		 */
		bindListEvent: function (){
			spxautocomplete.JQ(document).keyup(function(e) {	
			  switch(e.keyCode) { 
			      case 38:// User pressed "up" arrow
			         spxautocomplete.prototype.navigate('up');
			      break;
			      case 40:// User pressed "down" arrow
			    	  spxautocomplete.prototype.navigate('down');
			      break;
			      case 13:// User pressed "enter"
			         if(spxautocomplete.currentValue != '') {
			        	 spxautocomplete.JQ(spxautocompleteconfig.autoCompleteField).text(spxautocomplete.currentValue);
			        	 spxautocomplete.currentSelection = -1;
			        	 spxautocomplete.currentValue="";
			         }
			      break;
			  }	
		   });
		},
		
		/**
		 * This will handle hover event caused by mouse
		 */
		bindHoverEvent: function(){
			// Add data to let the hover know which index they have
			for(var i = 0; i < spxautocomplete.JQ("#"+spxautocomplete.autoSuggestionsList+" li").size(); i++) {
				spxautocomplete.JQ("#"+spxautocomplete.autoSuggestionsList+" li").eq(i).data("number", i);
			}	
			// Simulate the "hover" effect with the mouse
			spxautocomplete.JQ("#"+spxautocomplete.autoSuggestionsList+" li").hover(
				function () {
					spxautocomplete.currentSelection = spxautocomplete.JQ(this).data("number");
					spxautocomplete.prototype.setSelected(spxautocomplete.currentSelection);
				}, function() {
					spxautocomplete.JQ("#"+spxautocomplete.autoSuggestionsList+" li").removeClass(spxautocompleteconfig.listItemHoverClass);
					spxautocomplete.currentValue = '';
				}
			);
		   
			
		},
		
		
		/**
		 * This method sends cross-domain AJAX requests for the provided input.
		 * @param value
		 */
		lookup: function(value) {
			if (spxautocomplete.JQ.trim(value).length < 2) {
				spxautocomplete.JQ("#"+spxautocomplete.autoCompleteSuggestionsBox).hide();
			} else {
				if(spxautocomplete.JQ("#ignoreme").val()==''){
					spxautocomplete.prototype.crossDomainAJAX(value);
					spxautocomplete.currentSelection = -1;
		        	spxautocomplete.currentValue="";					
				}
			}
		},		
		

		/**
		 * This method fills the input text field with the value selected from list.
		 * @param value
		 * 
		 */
		fill: function(value) {
			spxautocomplete.JQ(spxautocompleteconfig.autoCompleteField).val(unFixQuotes(value));
			setTimeout("spxautocomplete.JQ('#"+spxautocomplete.autoCompleteSuggestionsBox+"').hide();", 150);
		},
		
		/**
		 * This mehtod sends cross-domain AJAX request and returns a JSON object in a callback() method.
		 * @param value
		 * 
		 */
		crossDomainAJAX: function(value) {
			var serverURL = spxautocompleteconfig.serverURL+"&maxSize="+spxautocompleteconfig.RESPONSE_KEYWORDS_SIZE+"&value="+ encodeURIComponent(value)+"&authKey="+spxautocompleteconfig.AUTH_KEY+"&locale="+spxautocompleteconfig.LOCALE;
			
			jQuery.ajax({ 
						url: serverURL,
				        dataType: "jsonp",
				        jsonp: 'spxautocomplete.prototype.callback',
				        success: function(json) {
				 			spxautocomplete.prototype.callback(json);
				        }
			 		});
			
			
		},
		
		/**
		 * This will handle events caused by keyboard navigation
		 * @param direction
		 * 
		 */
		navigate: function(direction) {
		   // Check if any of the menu items is selected
		   if(spxautocomplete.JQ("#"+spxautocomplete.autoSuggestionsList+" li."+spxautocompleteconfig.listItemHoverClass+"").size() == 0) {
			   spxautocomplete.currentSelection = -1;
		   }
		   if(direction == 'up' ) {
			   if(!(spxautocomplete.currentSelection <= 0)) {
				   spxautocomplete.currentSelection--;
			  }else{
				  spxautocomplete.currentSelection = spxautocomplete.JQ("#"+spxautocomplete.autoSuggestionsList+" li").size() -1;
			  }
		   } else if (direction == 'down') {
		      if(spxautocomplete.currentSelection != spxautocomplete.JQ("#"+spxautocomplete.autoSuggestionsList+" li").size() -1) {
		    	  spxautocomplete.currentSelection++;
		      }else{
		    	  spxautocomplete.currentSelection = 0;
		      }
		   }
		   spxautocomplete.prototype.setSelected(spxautocomplete.currentSelection);
		},
		
		/**
		 * This method maintains the navigation selected item
		 * @param menuitem
		 * 
		 */
		setSelected: function(menuitem) {
			spxautocomplete.JQ("#"+spxautocomplete.autoSuggestionsList+" li").removeClass(spxautocompleteconfig.listItemHoverClass);
			spxautocomplete.JQ("#"+spxautocomplete.autoSuggestionsList+" li").eq(menuitem).addClass(spxautocompleteconfig.listItemHoverClass);
		    spxautocomplete.currentValue = spxautocomplete.JQ("#"+spxautocomplete.autoSuggestionsList+" li").eq(menuitem).attr("onclick");

		},
		
		/**
		 * The callback method is returned in JSON from AJAX which executes itself as soon as response arrives.
		 * @param data
		 * @return
		 */
		callback: function(data) {
			var error;
			if(data.error){
				error = true;
			}
			
			if(!error){
				var input = spxautocomplete.JQ(spxautocompleteconfig.autoCompleteField).val().toLowerCase();
				if(data.keywordList.length > 0) {
					if(data.keyword.toLowerCase() == input){
						var elem = "";
						spxautocomplete.JQ.each(data.keywordList, function(i, keyword) {
							var styledKeyword = "";
							
							//Adding space in the start of the keyword temporarily.
							var keyword1 = " "+keyword.keyword.toLowerCase();
							var inputLenght = input.length;
							var index = keyword1.indexOf(" "+input);
							var oldIndex = 0;
							do{
								if(index!=oldIndex){
									if(styledKeyword.length > 0){
										styledKeyword += "<b>"+keyword.keyword.substring(oldIndex+inputLenght, index)+"</b>";
									}else{
										styledKeyword += "<b>"+keyword.keyword.substring(oldIndex, index)+"</b>";	
									}
								}
								styledKeyword += keyword.keyword.substring(index, index+inputLenght);
								oldIndex = index;
								index = keyword1.indexOf(" "+input, oldIndex+1);
							}while(index > -1);
							
							styledKeyword += "<b>"+keyword.keyword.substring(oldIndex+inputLenght)+"</b>"
							elem += "<li id='keywordElement' onclick='spxautocomplete.prototype.fill(\""+ fixQuotes(keyword.keyword) + "\"); spxautocompleteconfig.prototype.defaultSearch(\""+ fixQuotes(keyword.keyword) + "\");'>";
							elem += spxautocomplete.JQ.trim(styledKeyword) + "</li>";
						});
	
						spxautocomplete.JQ("#"+spxautocomplete.autoSuggestionsList).text("");						
						spxautocomplete.JQ(elem).appendTo("#"+spxautocomplete.autoSuggestionsList);
						elem = "";
	
						if (spxautocomplete.JQ.trim(spxautocomplete.JQ("#"+spxautocomplete.autoSuggestionsList).text()) === "") {
							spxautocomplete.JQ("#"+spxautocomplete.autoCompleteSuggestionsBox).hide();
						} else {
							spxautocomplete.prototype.bindHoverEvent();
							spxautocomplete.JQ("#"+spxautocomplete.autoCompleteSuggestionsBox).show();
						}
					}
				}else{
					spxautocomplete.JQ("#"+spxautocomplete.autoCompleteSuggestionsBox).hide();
				}
			}else{
				if(spxautocompleteconfig.DEBUG_MODE == 1)
					spxautocomplete.prototype.errorHandler(data);
			}
		},
		
		errorHandler: function(errorJSON){
			alert(errorJSON.error + ": "+ errorJSON.error_description+", ERROR_CODE:"+ errorJSON.error_code);
		}		
};

function fixQuotes(value) {
    // replace all the single, double quotes:
    var val = value.replace(/\'/g, "#39;");
    val = val.replace(/\"/g, "#34;");
	 return val;
}

function unFixQuotes(value) {
    // replace all the single, double quotes:
    var val = value.replace(/#39;/g, "\'");
    val = val.replace(/#34;/g, "\"");
    return val;
}

this.$ = spxautocomplete.JQ;
