/**
 * Fredhopper search suggestion
 * 
 * @author		dean.kostovski
 */


(function (jQuery) {
	//Extend the jQuery object
	jQuery.fn.searchSuggest = function (options) {
		options = jQuery.extend({
			formSelector: '#searchForm', // selector for the search form
			inputSelector: '#searchForm > #search', // selector for the input field
			containerSelector: '#search-suggestions', // container for the suggestions
			selectedClass: 'selected', // Class attached to the selected item
			scope: '//products/de_CH', // Fredhopper scope. Use this parameter for language selection
			serverUrl: '', // Fredhopper suggestion server url
			hideTitles: [], //titles for groups we don't want to be displayed
			replaceTitles: {}, //titles to be replaced
			onSubmit: function(form){} //action executed on form submit
			
		}, options);
		
		var KEY = {
				UP: 38,
				DOWN: 40,
				LEFT: 37,
				RIGHT: 39,
				DEL: 46,
				RETURN: 13,
				ESC: 27,
				PAGEUP: 33,
				PAGEDOWN: 34,
				BACKSPACE: 8,
				HOME:36,
				END:35,
				SHIFT:16,
				INSERT:45,
				CAPS:20,
				CTRL:17,
				ALT:18,
				NUMLOCK:144
			};
		
		//create the arrays and set the listeners
		var form = jQuery(options.formSelector);
		var input = jQuery(options.inputSelector);
		var items = jQuery(options.containerSelector + ' ul li a');
		var selected = null;
		var originalValue = null;
		jQuery(options.containerSelector).hide();
		init();

		jQuery(document).click(function(){
			jQuery(options.containerSelector).hide();
		});

		jQuery(form).submit(function (event) {
			jQuery(options.containerSelector).hide();
			if (selected != null) {
				form.find('input[name=suggestionType]').val(selected.find('input[name=suggestionType]').val());
				form.find('input[name=suggestionValue]').val(selected.find('input[name=suggestionValue]').val());
			}
			return options.onSubmit.call(this, form);
		});
			
		
		//Keyboard event
		input.keydown(function(ev) {
			if (ev.keyCode == KEY.RETURN) {
				return true;
			}
			else if (ev.keyCode == KEY.LEFT || ev.keyCode == KEY.RIGHT) {
				//don't refresh the suggest list on left and right arrows
				return true;
			} else if ((ev.keyCode == KEY.UP || ev.keyCode == KEY.DOWN)) {
				if (jQuery(options.containerSelector).is(":visible")) {
					var index = -1;
					if (selected != null) {
						index = items.index(selected);
					}
					if (ev.keyCode == KEY.UP) {
						if (index == -1) {
							index = items.size() - 1;
						} else {
							index--;
							if(index < 0) {
								index = -1;
							}
						}
					} else {
						if (index == -1) {
							index = 0;
						} else {
							index++;
							if(index >= items.size()) {
								index = -1;
							}
						}
					}
					
					var newSelected = null;
					if (index != -1) {
						newSelected = jQuery(items[index]);
						setTextInputValue(extractText(newSelected));
					} 
					changeSelectedAndUpdateValue(newSelected);
					
					return false;
				}
			} else if (ev.keyCode == KEY.ESC) {
				jQuery(options.containerSelector).hide();
				jQuery(options.input).val("");
			} else {
				switch (ev.keyCode) {
					case KEY.LEFT:
					case KEY.RIGHT:
					case KEY.HOME:
					case KEY.END:
					case KEY.PAGEUP:
					case KEY.PAGEDOWN:
					case KEY.SHIFT:
					case KEY.INSERT:
					case KEY.CAPS:
					case KEY.CTRL:
					case KEY.ALT:
					case KEY.NUMLOCK:
						break;
					case KEY.DEL:
					case KEY.BACKSPACE:
						if (input.val().length <= 1) {
							jQuery(options.containerSelector).hide();
							break;
						}
					default:
						//give some time for the input value to be updated
						setTimeout(askForUpdateSuggestWithDefaultVaue, 250);
				}
			}
			return true;
		});
		
		/*init the items. Gets the li's and attach them listeners*/
		function init() {
			items = jQuery(options.containerSelector + ' ul li a');
			//Mouse events
			items.mouseenter(function() {
				var item = jQuery(this);
				changeSelected(item)
			});
			items.click(function() {
				var item = jQuery(this);
				changeSelectedAndUpdateValue(item)
				jQuery(options.containerSelector).hide();
				form.submit();
				return false;
			});
			selected = null;
			originalValue = input.val();
		}
		
		
		function changeSelectedAndUpdateValue(item) {
			changeSelected(item);
			if (item != null) {
				setTextInputValue(extractText(item));
			} else {
				setTextInputValue(originalValue);
			}
		};
		function changeSelected(item) {
			items.removeClass(options.selectedClass);
			selected = item;
			if (item != null) {
				item.addClass(options.selectedClass);
			}
		};
		
		function setTextInputValue(value) {
			return input.val(value);
		};
		
		/*Extract text from list item.*/
		function extractText(item) {
			var copy = jQuery(item.children()[0]);
			return jQuery.trim(copy.text());
		}
		
		
		var requestActive = false;
		var requestQueued = false;
		var maxWaitTime;
		
		/*Asks for new update from the suggest server*/
		function askForUpdateSuggestWithDefaultVaue() {
			originalValue = input.val();
			askForUpdateSuggest(originalValue);
		}
		/*Checks if a request to the suggest server is already active. If not puts a request in a queue*/
		function askForUpdateSuggest(value) {
			if (!requestActive) {
				requestActive = true;
				updateSuggest(value);
				maxWaitTime=setTimeout(updateSuggestTimeout, 2000)
			} else {
				requestQueued = true;
			}
		}
		function checkForUpdateSuggest() {
			if (!requestActive && requestQueued) {
				requestQueued = false;
				askForUpdateSuggestWithDefaultVaue();
			}
		}
		
		function updateSuggestTimeout() {
			requestActive = false;
			checkForUpdateSuggest();
		}
		
		/*Make the request to the suggest server and prepare the data for display*/
		function updateSuggest(value) {
			jQuery.ajax({
				  dataType: 'jsonp',
				  data: 'scope=' + options.scope + '&search=' + value,
				  jsonp: 'callback',
				  url: options.serverUrl,
				  success: function (data) {
					setTimeout(updateSuggestTimeout, 300);
					clearTimeout(maxWaitTime);
					data = filterResults(data);
					renderDropdown(data);
				  }
				});
		}
		
		/*Remove the groups that don't satisfy all the conditions*/
		function filterResults(data) {
			var groups = data.suggestionGroups;
			var newGroups = [];
			var newData = new Object();
			for (var index in groups) {
				var group = groups[index];
				if (jQuery.inArray(group.indexName, options.hideTitles) != -1) {
					group.indexName = '';
					group.indexTitle = '';
				}
				
				if (options.replaceTitles[group.indexTitle] != null) {
					group.indexName = options.replaceTitles[group.indexTitle];
					group.indexTitle = options.replaceTitles[group.indexTitle];
				}
				
				if(isValidGroup(group)) {
					newGroups.push(group);
				}
			}
			newData.suggestionGroups = newGroups;
			return newData;
		}
		
		/*Is a group valid?*/
		function isValidGroup(group) {
			try {
				if (group.suggestions[0].searchterm != null || 
						group.suggestions[0].fhLocation != null || group.suggestions[0].variant_id != null) {
					return true;
				}
			} catch (e) {}
			return false;
		}
		
		function createHiddenFileds(parent, type, value) {
			var suggestionType = document.createElement("input");
			var suggestionValue = document.createElement("input");
			suggestionType.type = suggestionValue.type = "hidden";
			suggestionType.name = "suggestionType";
			suggestionValue.name = "suggestionValue";
			suggestionType.value = type;
			suggestionValue.value = value;
			parent.appendChild(suggestionType);
			parent.appendChild(suggestionValue);
		}
		
		function addKeyword(parent, suggestion) {
			var a = document.createElement("a");
			a.href = "#";
			a.innerHTML = '<span>' + suggestion.searchterm  + '</span><span class="count">(' + suggestion.nrResults + ')</span>';
			createHiddenFileds(a, "", "");
			parent.appendChild(a);
		}
		
		function addCategory(parent, suggestion) {
			var a = document.createElement("a");
			a.href = "#";
			var text;
			if (suggestion.mlValue.length > 25) {
				text = jQuery.trim(suggestion.mlValue.substring(0, 25)) + " (...)"; 
			} else {
				text = suggestion.mlValue;
			}
			a.innerHTML = '<span style="display: none">' + suggestion.mlValue  + '</span><span>' + text  + '</span><span class="count">(' + suggestion.nrResults + ')</span>';
			createHiddenFileds(a, "category", suggestion.fhLocation);
			parent.appendChild(a);
		}
		
		function addProduct(parent, suggestion) {
			var a = document.createElement("a");
			var formattedPrice = suggestion.price.replace(/\.0+$/, ".-");
			a.innerHTML = '<span style="display: none">' + suggestion.title + '</span>';
			a.innerHTML += '<span class="miniProdTeaser"><img alt="' + suggestion.title + '" src="' + suggestion.image + '" width="50" height="50" /><h4>' + 
							suggestion.title + '</h4><p><span class="price">' + formattedPrice + '</span></p></span>';
			createHiddenFileds(a, "product", suggestion.variant_id);
			parent.appendChild(a);
		}
		
		/*renders the suggestion dropdown*/
		function renderDropdown(data) {
			var container = jQuery(options.containerSelector);
			container.empty();
			if(data.suggestionGroups.length != 0) {
				for (var i = 0; i < data.suggestionGroups.length; i++) {
					var group = data.suggestionGroups[i];
					var div = document.createElement("div");
					div.setAttribute("class", "group");
					div.innerHTML = "<h3>" + group.indexName + '<span class="count">(' + group.suggestions.length + ")</span></h3>";
					var ul = document.createElement("ul");
					for (var j = 0; j < group.suggestions.length; j++) {
						var suggestion = group.suggestions[j];
						var li = document.createElement("li");
						if (suggestion.searchterm != null) {
							addKeyword(li, suggestion);
						} else if (suggestion.fhLocation != null) {
							addCategory(li, suggestion);
						} else if (suggestion.variant_id != null) {
							addProduct(li, suggestion);
						}
						ul.appendChild(li);
					}
					div.appendChild(ul);
					container.append(div);				
				}
				init();
				container.show();
			} else {
				container.hide();
			}
		}
		return this;
	};
})(jQuery);
