var QuickSearch = Class.create({
	
	options: {
		searchView: 'items',
		searchButtonTitle: 'Search',
		keywordSeparator: 'OR',
		keywordLabel: 'Keyword Search'
	},
	
	initialize: function(surface, results_surface, options)
	{
		this.ui_surface = $(surface);
		this.results_surface = $(results_surface);
		
		if(Object.isUndefined(this.ui_surface))
		{
			// console.log("QuickSearch: No surface provided");
			return;
		}
		
		if(Object.isUndefined(this.results_surface))
		{
			// console.log("QuickSearch: No results surface provided");
			return;
		}
		
		this.ui_surface.addClassName('qs-surface');
		
		this.surface = Builder.node('form');
		this.surface.observe('submit', function(event) {event.stop();});
		this.ui_surface.insert(this.surface);
		
		this.options = Object.extend(this.options, options);
		
		// Create the object rendering
		this.filtersDiv = Builder.node('div', {id: 'qs-filters'});
		this.surface.insert(this.filtersDiv);
		
		// The Selected Keywords List
		this.keywordsSelectedList = Builder.node('ul', {id: 'qs-keywords-selected'});
		this.surface.insert(this.keywordsSelectedList);
		
		// The DIV Containing the Search <input> and suggestions
		this.keywordSearchDiv = Builder.node('div', {id: 'qs-keywords'});
		this.surface.insert(this.keywordSearchDiv);
		
		this.keywordSeparator = Builder.node('span', {'class': 'separator'}, this.options.keywordSeparator);
		this.keywordSearchDiv.insert(this.keywordSeparator);		
		
		this.keywordLabel = Builder.node('label', {'for': 'qs-keyword-input'}, this.options.keywordLabel);
		this.keywordSearchDiv.insert(this.keywordLabel);
		
		this.keywordInput = Builder.node('input', {id: "qs-keyword-input", name: 'qs-keyword-input', className: 'text'});
		this.keywordInput.observe('keyup', this.keyboardInput.bindAsEventListener(this));
		this.keywordSearchDiv.insert(this.keywordInput);
		
		// The suggestions list
		this.suggestionsList = Builder.node('ul', {className: 'qs-suggestions'});
		this.keywordSearchDiv.insert(this.suggestionsList);
		
		this.searchButton = Builder.node('input', {type: 'button', value: this.options.searchButtonTitle});
		this.searchButton.addClassName("qs-search-button");
		this.searchButton.observe('click', this.search.bindAsEventListener(this));
		this.keywordSearchDiv.insert(this.searchButton);
		
		// Request the filters from the server
		this.requestFilters();
		
		document.observe('quicksearch:clear', this.clear.bindAsEventListener(this));
		document.observe('quicksearch:changed', this.filtersChanged.bindAsEventListener(this));
		
		// Required instance variables
		this.currentlySelectedIndex = -1;
		this.selections = new Array();
		this.suggestions = new Array();
		// Allow the UI to display the number of items
		this.filtersChanged();
	},
	
	filtersChanged: function(event)
	{
		this.requestCount();
	},
	
	// Clear Keywords and Suggestions
	clear: function(event)
	{
		this.clearSuggestions();
		this.clearKeywords();
	},
	
	clearSuggestions: function()
	{
		this.keywordInput.value = '';
		this.suggestions.length = 0;
		this.suggestionsList.update();
		this.currentlySelectedIndex = -1;
	},
	
	// Re-render the Suggestions
	updateSuggestions: function()
	{
		this.suggestionsList.update();
		var index = 0;
		this.suggestions.each( function(word) {
			var oldWord = word;
			word = this.prepForDisplay( word );
			
			var li = Builder.node('li', {className: 'qs-suggestion'}, word);
			
			if(index == this.currentlySelectedIndex)
				li.addClassName('selected');
			else
				li.removeClassName('selected');
			
			this.suggestionsList.insert(li);
			
			li.observe('click', this.suggestionSelected.curry(oldWord).bind(this));
			
			li.observe('mouseover', function(index, event){
				var i=0;
				this.suggestionsList.childElements().each(function(li){
					if(i++ == index)
						li.addClassName('selected');
					else
						li.removeClassName('selected');
				});
			}.curry(index).bind(this));
			
			li.observe('mouseout', function(index, event){
				var i=0;
				this.suggestionsList.childElements().each(function(li){
					if(i++ == index)
						li.removeClassName('selected');
				});
			}.curry(index).bind(this));
			
			index++;
		}.bind(this));
	},
	
	// Re-render the Keywords
	updateKeywords: function()
	{
		this.keywordsSelectedList.update();
		
		this.selections.each(function(kw){
			var li = Builder.node('li', {});
			
			kw = this.prepForDisplay( kw );
			
			var close = Builder.node('span', {className: 'qs-close'}, "[x]");
			li.insert(close);
			close.observe('click', this.removeSelectedKeyword.curry(kw).bindAsEventListener(this));

			var title = Builder.node('span', {}, kw);
			li.insert(title);
			
			this.keywordsSelectedList.insert(li);
		}.bind(this));
	},
	
	// Remove all the Keywords
	clearKeywords: function()
	{
		this.selections = new Array();
		this.keywordsSelectedList.update();
	},
	
	keyboardInput: function(e)
	{
		if(e.keyCode == 38 || e.keyCode == 40)
		{
			//Handle UP/DOWN actions
			
			if(e.keyCode == 38)
			{
				this.currentlySelectedIndex--;
				
				if(this.currentlySelectedIndex < 0)
					this.currentlySelectedIndex = 0;
			}
			else if(e.keyCode == 40)
			{
				this.currentlySelectedIndex++;
				
				if(this.currentlySelectedIndex >= this.suggestions.length)
					this.currentlySelectedIndex = this.suggestions.length - 1;	
			}
			
			this.updateSuggestions();
			
			return;
		}
		
		if(e.keyCode == 13 && this.currentlySelectedIndex >= 0)
		{
			// Handle Enter action
			if(this.suggestions.length > 0)
				this.suggestionSelected(this.suggestions[this.currentlySelectedIndex]);
				
			return;
		}
		
		if(e.keyCode == 27)
		{
			// Handle escape action
			this.keywordInput.value = '';
			this.clearSuggestions();
			
			return;	
		}
		this.requestCount();
		// Cancel the time as the user has started typing again
		clearTimeout(this.input_timeout);
		
		// Restart the timeout as the user has stopped typing
		this.input_timeout = setTimeout(this.requestSuggestions.bind(this), 200);
	},
	
	// Select a suggestion
	suggestionSelected: function(keyword)
	{
		this.selections.push(keyword);
		this.updateKeywords();
		this.clearSuggestions();
		
		this.requestCount();
		
		this.currentlySelectedIndex = -1;
	},
	
	removeSelectedKeyword: function(keyword, event)
	{
		keyword = this.prepForSend( keyword );

		var newSelections = new Array();
		this.selections.each(function(kw){
			if(kw != keyword)
				newSelections.push(kw);
		});
		this.selections = newSelections;
		this.updateKeywords();
		
		this.requestCount();
	},
	
	// Get an array of all the tags currently set by the Filters
	getTagsFromFilters: function()
	{
		var tags = new Array();
		var str = '';
		for(filterName in this.filters)
		{
			var filter = this.filters[filterName];
			if(str.length) { str += ':'; }
			tags = tags.concat(filter.getTags());
		}
		return tags;
	},
	
	search: function()
	{
		var url = "/quicksearch/search";
		
		var searchterms = this.getTagsFromFilters();
		
		searchterms = searchterms.concat(this.selections);
		
		if (this.suggestions.length == 1) 
		{
			searchterms = searchterms.concat(this.suggestions);
		}

		// Replace whitespace with +
		var params = "";
		for(var i=0; i < searchterms.length; i++)
		{
			if(i > 0)
				params += ', ';
				
			params += searchterms[i].replace(/\s/g, '_');
		}
		
		new Ajax.Updater(this.results_surface, url, {
			  method: 'post',
			  parameters: 'tags='+params+'&searchview='+this.options.searchview,
			  evalScripts: true,
			onComplete: function() { document.fire('quicksearch:complete'); }
		});
	},
	
	// Redraw the Filters
	render: function()
	{
		this.filtersDiv.update();
		for(filterTitle in this.filters)
		{
			var filter = this.filters[filterTitle];
			filter.render();
			this.filtersDiv.insert(filter.getSurface());
		}
	},
	
	/* --- AJAX FUNCTIONS --- */
	
	requestSuggestions: function()
	{
		keywordinput = this.prepForSend( this.keywordInput.value );
		
		if(!keywordinput)
		{ 
			this.clearSuggestions();
			return;
		}
		
		var url = '/quicksearch/suggest';
		
		var searchterms = this.getTagsFromFilters();
		
		// Replace whitespace with +
		var params = "";
		for(var i=0; i < searchterms.length; i++)
		{
			if(i > 0)
				params += ', ';
			
			params += this.prepForSend( searchterms[i] );
		}
		
		var exclude = "";
		for(var j=0; j < this.selections.length; j++)
		{
			if(j > 0)
				exclude += ', ';
				
			exclude += this.prepForSend( this.selections[j] );
		}
		
		// console.log('tags='+params+'&input='+keywordinput+'&selected='+exclude);
		new Ajax.Request(url, {
		  method: 'post',
		  parameters: 'tags='+params+'&input='+keywordinput+'&selected='+exclude,
		  onSuccess: this.requestSuggestionsResponse.bind(this)
		});
	},
	
	requestSuggestionsResponse: function(transport)
	{
		var json = transport.responseText.evalJSON();
		// console.log(json);
		
		if(json)
		{
			this.suggestions = json.suggestions;
			this.updateSuggestions();
		}
	},
	
	requestCount: function()
	{
		var url = "/quicksearch/search";
		
		var searchterms = this.getTagsFromFilters();
		
		searchterms = searchterms.concat(this.selections);
		
		// Replace whitespace with +
		var params = "";
		for(var i=0; i < searchterms.length; i++)
		{
			if(i > 0)
				params += ', ';
				
			params += this.prepForSend( searchterms[i] );
		}
		
		new Ajax.Request(url, {
		  method: 'post',
		  parameters: 'tags='+params+'&format=json',
		  onComplete: this.requestCountResponse.bind(this)
		});
	},
	
	prepForSend: function( word )
	{
		word = word.toLowerCase();
		
		var reg = /([a-z\s]+) \(([a-z\+]+)\)/g;
		var matches = reg.exec(word);
		if(matches && matches.length)
		{
			word = matches[2]+":"+matches[1];
		}
		word = word.replace(/\s/g, '+');
		
		return word;
	},
	
	prepForDisplay: function(word)
	{
		var reg = /([a-z])([a-z\+]+)\:(.*)/g;
		var matches = reg.exec(word);
		if(matches && matches.length)
		{
			word = matches[3]+' ('+matches[1].toUpperCase()+matches[2]+')';
		}
		
		word = word.replace(/_/g, ' ');
		word = word.replace(/\+/g, ' ');
		
		return word;
	},
	
	requestCountResponse: function(transport)
	{
		var json = transport.responseText.evalJSON();
		
		if(json)
		{
			document.fire('quicksearch:suggestioncount', json);
		}
	},
	
	requestFilters: function()
	{
		new Ajax.Request("/quicksearch/getfilters", {
		  method: 'post',
		  onSuccess: this.requestFiltersResponse.bind(this)
		});
	},
	
	requestFiltersResponse: function(transport)
	{
		var json = transport.responseText.evalJSON();
		
		this.filters = new Object();
		
		// Create a QuickSearchFilter object from each JSON filter
		json.each( function(filterJSON) {
			var filter = new QuickSearchFilter(filterJSON);
			this.filters[filterJSON.label] = filter;
		}.bind(this));
		
		// Make sure dependants are setup
		json.each( function(filterJSON) {
			var filter = this.filters[filterJSON.label];
			
			if(filter && filter.sub_filter && this.filters[filter.sub_filter])
			{
				var sub_filter = this.filters[filter.sub_filter];
				filter.addDependant(sub_filter);
				
				// Remove the sub filter from the top level as the parent filter will handle it!
				delete this.filters[sub_filter.label];
			}
		}.bind(this));
		
		this.render();
	}
	
});


