; // Yes, a random semicolon IS needed here, it's a jQuery thing.


//Define the default options for each readonly overlay object.
//In addition to other static methods.
window.com_blindacre_autocompleter_obj = window.com_blindacre_autocompleter_obj || {
	defaults: {
		inputClass: "bamac_input",
		resultsClass: "bamac_results",
		loadingClass: "bamac_loading",
		minChars: 1,
		formatTitle: "#title#",
		formatValue: "#value#",
		delay: 200,
		
		_dummy: false
	},
	
	handleElement: function(el, opts){
		/*console.log('@todo do the attach logic.');
		console.log(el);
		console.log(opts);*/
		
		var actualEl;
		
		if(typeof(el.jquery) == 'undefined'){
			// el is an actual DOM node!
			actualEl = el;
		}
		else{
			actualEl = el[0];
		}
		
		// Try to reuse an existing object if it is bound to the dom node.
		if(typeof(actualEl.com_blindacre_autocompleter) == 'undefined'){
			var obj = new com_blindacre_autocompleter;
			obj.setElement(el, opts);
		}
	},
	

	// KEEP THIS THE LAST ELEMENT
	//  It's a trick to prevent the final-comma error in IE.
	_dummy: false
};



//Each individual readonly instance will be its own version of this object.
//This allows for a greater amount of flexibility for defining options.
function com_blindacre_autocompleter(){
	
	this.KEY = {
		UP: 38,
		DOWN: 40,
		DEL: 46,
		TAB: 9,
		RETURN: 13,
		ESC: 27,
		COMMA: 188,
		PAGEUP: 33,
		PAGEDOWN: 34,
		BACKSPACE: 8
	};
	
	this.options = false;
	
	// The XMLHTTPRequest object, useful for canceling requests.
	this._request = false;
	
	// The string of the last query, useful for verifying correct response.
	this._lastRequest = false;
	
	// Will act as a cache for results.  Saving a result will prevent in duplicate requests to the server.
	this._cache = [];
	
	// The component do display the results in.  Created dynamically.
	this._output = false;
	
	this.$input = false;
	
	// The delay timer.
	this._timer = false;
	
	this.setElement = function(i, o){
		
		this.options = o;
		
		this.$input = jQuery(i);
		this.$input[0].com_blindacre_autocompleter = this;
		
		// Attach the events required onto the input.
		this.$input.keyup(function(e){
			
			// A few special-case keystrokes, inlcuding esc and down/up arrows.
			switch(e.keyCode){
				case this.com_blindacre_autocompleter.KEY.ESC:
					this.com_blindacre_autocompleter._closeResults();
					return;
			}
		
			// Use direct variable access, quicker then jquery.
			var target = e.currentTarget;
			
			target.com_blindacre_autocompleter.setLoadingClass();
			
			function changeEvent(){
				target.com_blindacre_autocompleter._getResults(target.value);
			}
			
			clearTimeout(this.com_blindacre_autocompleter._timer);
			this.com_blindacre_autocompleter._timer = setTimeout(changeEvent, this.com_blindacre_autocompleter.options.delay);
		}).click(function(e){
			// Use direct variable access, quicker then jquery.
			var target = e.currentTarget;
			
			target.com_blindacre_autocompleter.setLoadingClass();
			
			function changeEvent(){
				target.com_blindacre_autocompleter._getResults(target.value);
			}
			
			clearTimeout(this.com_blindacre_autocompleter._timer);
			this.com_blindacre_autocompleter._timer = setTimeout(changeEvent, this.com_blindacre_autocompleter.options.delay);
		});
	};
	
	// Some CSS helper functions.
	this.setLoadingClass = function(){
		this.$input.addClass(this.options.loadingClass);
	}
	this.unsetLoadingClass = function(){
		this.$input.removeClass(this.options.loadingClass);
	}
	
	this._getResults = function(v){
		
		if(!v){
			this._closeResults();
			return;
		}
		
		// Cancel any current request that may be out.
		//if(this._request) this._request.abort();
		this._request = false;
		this._lastRequest = false;
		
		if(typeof this._cache[v] != 'undefined'){
			this._displayResults(this._cache[v]);
			return;
		}
		
		this._lastRequest = v;
		
		this._request = $.ajax({
			url: this.options.url,
			data: 'q=' + v,
			dataType: 'json',
			originalObj: this,
			success: function(data, textStatus, xhr){
				// Not the request the browser thought it was?... np
				if(this.originalObj._lastRequest != data.search) return;
				
				// Set the request object to false, to let any further keystroke that it does not need to cancel it.
				this.originalObj._request = false;
				this.originalObj._lastRequest = false;
				
				// Save the results.
				this.originalObj._cache[data.search] = data;
				
				// And now do the display function.
				this.originalObj._displayResults(data);
			},
			error: function(xhr, textStatus, errorThrown){
				// Not the request the browser thought it was?... np
				if(this.originalObj._request != xhr) return;
				
				this.originalObj._request = false;
				
				// Well, I need to display SOMETHING to the user...
				data = {
					error: textStatus
				};
				
				this.originalObj._displayResults(data);
			}
		});
	};
	
	this._displayResults = function(data){
		if(!this._output){
			// Ok, just create it real quick.
			this._output = $('<ul class="' + this.options.resultsClass + '" style="display:block;"/>');
			//this.$input.after(this._output);
			$('#locations_popup').append(this._output);
		}
		
		// Clear all/any children in the element.
		this._output.html('');
		
		// Display nothing if not location search
		if (!$('input[value="locations"]').is(':checked')) return;
		
		// See if there's an error first.
		if(typeof data.error != 'undefined'){
			this._output.append('<li>' + data.error + '</li>');
			this.unsetLoadingClass();
			return;
		}
		
		
		for(i in data.results){
			title = this.options.formatTitle;
			value = this.options.formatValue;
			
			for(x in data.results[i]){
				re = new RegExp("#" + x + "#", 'g');
				title = title.replace(re, data.results[i][x]);
				value = value.replace(re, data.results[i][x]);
			}
			
			// Lastly, clean any quotes from the value.
			value = value.replace('"', '\"');
			this._output.append('<li serachval="' + value + '">' + title + '</li>');
		}
		
		this.unsetLoadingClass();
	};
	
	this._closeResults = function(){
		if(this._output){
			this._output.remove();
			this._output = false;
		}
		this.unsetLoadingClass();
	}
}

(function(jQuery) {
  jQuery.extend(jQuery.fn, {
	// jQuery wrapper around the global handler object.
	bam_autocomplete : function(options) {
	  options = jQuery.extend({}, window.com_blindacre_autocompleter_obj.defaults, options);
	  
	  // Run through each element given in by the programmer.
	  jQuery(this).each(function(){
		  window.com_blindacre_autocompleter_obj.handleElement(this, options);
	  });
	  return this;
	}
  });
})(jQuery);


