$(function(){
	/**
	 * Quicksearch suggestions
	 */
	
	function SuggestControl(form, suggester) {
		that = this;
		this.mouseIn = false;
		this.form = form;
		
		// this object provides the suggestions
		this.suggester = suggester;
		
		// find text input of the form
		this.inputBox = $("input", this.form);
		// turn autocomplete off
		this.inputBox.attr("autocomplete", "off");
		// show sample query text when possible
		this.initSampleQuery();
		
		// add suggestbox to form
		this.suggestBox = this.createSuggestBox();
		
		// when text is typed in input box, fire keypress event
		this.inputBox.keyup( function(e){ that.keyPress(e); } );
		
		// when focus is lost, hide the suggestions box
		this.inputBox.blur( function(e){ 
				if (!that.mouseIn) 
					that.populateSuggest([]); 
		} );
	}
	
	SuggestControl.prototype = {
		// Adds suggestbox to form and returns it
		createSuggestBox: function() {
			this.inputBox.after("<table class='suggest'></table>");
			var suggestBox = $(".suggest", this.form);
			
			// position right below input box
			var inputOffset = this.inputBox.offset();
			inputOffset.top += this.inputBox.height() + 7;
			suggestBox.css(inputOffset);
			
			return suggestBox;
		},
		
		// fired when key is pressed in input box
		keyPress: function(event) {
			var keyCode = event.keyCode;

			if (keyCode == 38) { // key up
				this.selectPrevious();
			}
			else if (keyCode == 40) { // key down
				this.selectNext();
			}
			else {
				// get suggestions for the text in input box
				// and populate suggestions box with those
				var suggestions = this.suggester.getSuggestions( this.inputBox.val() );
				this.populateSuggest( suggestions );
				
				$("tr", this.suggestBox).mouseover(
					function(e) { 
						that.mouseIn = true;
						that.selectSibling($(this));
					} );
				$("tr", this.suggestBox).mouseout(
					function(e) { 
						that.mouseIn = false;
					} );
				$("tr", this.suggestBox).click(
					function(e) { 
						that.inputBox.val($('th', $(this)).text() );
						that.mouseIn = false;
						that.inputBox.blur();
						that.form.submit();
					} );
			}
		},
		
		// add suggestions to suggestions box (if already something exists, replace it)
		populateSuggest: function( suggestions ) {
			if (suggestions.length == 0) {
				this.suggestBox.empty();
				return;
			}
			
			var rows = "";
			var count;
			for (var i=0; i<suggestions.length; i++ ) {
				count = ngettext("1 result", "%d results", suggestions[i].count).replace("%d", suggestions[i].count);
				rows += "<tr><th>" + suggestions[i].name + "</th><td>" + count + "</td></tr>";
			}
			
			this.suggestBox.html( rows );
		},
		
		selectNext: function() {
			this.selectSibling("tr:first-child", "next");
		},
		
		selectPrevious: function() {
			this.selectSibling("tr:last-child", "prev");
		},
		
		selectSibling: function(lastSiblingSelector, siblingFun) {
			var oldSelection = $("tr.selected", this.suggestBox);
			var newSelection;
			
			// if nothing is selected, select last one
			if (!siblingFun) {
				newSelection = lastSiblingSelector;
				oldSelection.removeClass("selected");
				newSelection.addClass("selected");
				return ;
			}
			else if ( !oldSelection.length ) {
				newSelection = $(lastSiblingSelector, this.suggestBox);
				newSelection.addClass("selected");
			}
			// if first one is selected, unselect everything
			else if ( !oldSelection[siblingFun]().length ) {
				oldSelection.removeClass("selected");
			}
			// otherwise simply select next row
			else {
				oldSelection.removeClass("selected");
				newSelection = oldSelection[siblingFun]();
				newSelection.addClass("selected");
			}
			
			if (newSelection) {
				this.inputBox.val( $("th", newSelection).text() );
			}
		},
		
		// when page loads and inputBox is empty, display the sample text
		// when user focuses inputBox, the sample is hidden
		// when user unfocuses input, leaving it empty, the samlpe is shown again
		initSampleQuery: function() {
			that = this;
			this.inputBox.focus(function(){ that.hideSampleQuery(); } );
			this.inputBox.blur(function(){ that.showSampleQuery(); } );
			this.showSampleQuery();
		},
		
		// display sample query if text box is empty
		showSampleQuery: function() {
			if (this.inputBox.val() == "") {
				this.inputBox.val(gettext("For example: BMW -150000km 20000-80000EEK"));
				this.inputBox.addClass("sample-query");
				this.sampleQueryVisible = true;
			}
		},
		
		// hide sample query if sample is visible
		hideSampleQuery: function() {
			if (this.sampleQueryVisible) {
				this.inputBox.val("");
				this.inputBox.removeClass("sample-query");
				this.sampleQueryVisible = false;
			}
		}
	};
		
	function MakeAndModelSuggester(makes) {
		this.makes = makes;
		
		this.oldText = "";
		this.oldResult = makes;
	}
	
	MakeAndModelSuggester.prototype = {
		
		// returns suggestions as pairs of titles and counts, like:
		// {'title1': count1, 'title2': count2, ... }
		getSuggestions: function(text) {
			if (text == "") {
				return [];
			}
			
			// if we are not continuing old text, start with initial makes array
			if (!this.extendsOldText(text)) {
				this.oldResult = this.makes;
			}
			var result = this.filterMakes(this.oldResult, text);
			this.oldResult = result;
			this.oldText = text;
			
			return this.transform(result);
		},
		
		// filter out suggestions
		filterMakes: function(makes, text) {
			var pattern = new RegExp("^" + text, "i");
			var makeBegins, matches;
			var result = [];
			var make;
			
			for (var i=0; i<makes.length; i++) {
				make = makes[i];
				if ( pattern.test(make.name) ) {
					result.push(make);
				}
				makeBegins = RegExp("^" + make.name + " +(.*)$", "i");
				matches = makeBegins.exec(text);
				if ( matches ) {
					result.push({
						name: make.name,
						count: make.count,
						models: this.filterModels(make.models, matches[1])
					});
				}
			}
			
			return result;
		},
		
		// filter out suggestions
		filterModels: function(models, text) {
			var pattern = new RegExp("^" + text, "i");
			var result = [];
			var model;
			
			for (var i=0; i<models.length; i++) {
				model = models[i];
				if ( pattern.test(model.name) ) {
					result.push(model);
				}
			}
			
			return result;
		},
		
		transform: function(makes) {
			var transformed = [];
			var cnt = 0;
			var make;
			
			if (makes.length == 1) {
				return this.transformModels(makes);
			}
			else {
				return this.transformMakes(makes)
			}
		},
		
		transformMakes: function(makes) {
			var transformed = [];
			var make;
			// output makes
			for (var i=0; i<makes.length; i++) {
				make = makes[i];
				transformed.push({
					name: [make.name],
					count: make.count
				});
			}
			
			return transformed;
		},
		
		transformModels: function(makes) {
			var transformed = [];
			var make;
			var model;
			var cnt = 0;
			
			// output models
			for (var i=0; i<makes.length; i++) {
				make = makes[i];
				
				for (var j=0; j < make.models.length; j++) {
					model = make.models[j];
					
					transformed.push({
						name: make.name + " " + model.name,
						count: model.count
					});
					
					cnt++;
					if (cnt > 20) {
						break;
					}
				}
			}
			
			return transformed;
		},
		
		extendsOldText: function(text) {
			var pattern = new RegExp("^" + this.oldText, "i");
			return pattern.test(text);
		},
		
		toString: function(obj) {
			var str = "{";
			for (x in obj) {
				str += x + ":" + obj[x];
			}
			str += "}";
			return str;
		}
	};
	
	var suggester = new MakeAndModelSuggester( Makes );
	var suggestControl = new SuggestControl( $("#quick-search form"), suggester );
});