function Search() {
	//this.default_content = $(this.options.main_container).innerHTML;
	this.default_search_button_value  = $(this.options.search_button).value;
	this.search_form = $$("form."+this.options.search_form_class).first();
	this.init();
}
Search.prototype = {
	options: {
		main_container: 'content',
		search_form_class: 'search_form',
		search_button: 'search',
		new_search_button: 'new_search_button',
		error_block: 'user_error',
		content_wrapper: "content_wrapper"
	},
	geodistancer: new Geodistancer(),
	em: new EventManager(),
	//default_content: null,
	url: null,
	params: null,
	feedback: null,
	has_location: false,	
	init: function() {
		this.em.set(this.search_form, {submit: {action: this.run.bind(this), dispatch: true}});
		//this.em.set(this.options.new_search_button, {click: {action: this.displayForm.bind(this), dispatch: true}});		
		this.em.start();
	},
	reset: function() {
		this.em.unset();
		this.init();
		CheckboxEnhancer.reset();
		this.has_location = false;
		this.url = null;
		this.params = null;
		this.feedback = null;
		this.enableForm();
		this.writeStatus(this.default_search_button_value);
	},
	run: function(uri) {
		this.search_form_content = $(this.options.main_container).innerHTML; 
		this.writeStatus('Searching...');
		this.disableForm();
		this.url = uri.split(/\?/).first();
		this.params = uri.toQueryParams();
		this.has_location = this.geodistancer.hasLocation(this.params);
		this.getResults();
	},
	getResults: function(distances) {
		if($(this.options.error_block)) $(this.options.error_block).remove(); 
		var parameters = Object.extend(
		{
			ajax: true,
			has_location: (this.has_location) ? 1 : 0
		}, 
		this.params);
		if(distances != undefined) parameters.distances = Object.toJSON(distances); // push the distances array into parameters if we have it		 
		var get_distances = this.has_location && distances == undefined; // get distances if we have a location and it's not already sorted
		var request = new Ajax.Request(this.url, {
			method: 'get',
			parameters: parameters,
			onSuccess: function(transport) {
				var res = transport.responseText;
				if(get_distances) {
					var hash = (res != "[]") ? $H(res.evalJSON()) : new Hash();
					if (hash.size() > 0) {
						this.geodistancer.getDistances($H(parameters), hash, this._handleDistances.bind(this));
					} else {
						this.getResults(hash); // there is no valid geodata in the database, so just get the results with unknown distances
					}
				} else {
					this.update(res);
					this.reset();
				}
			}.bind(this),
			on400: function(transport) {
//				var msg =  "The following errors were encountered while trying to perform the search:\n\n";
//				msg 	+= transport.responseText.evalJSON().join("\n");
				if(!$(this.options.error_block)) {
					var error_block = new Element("ol");
					error_block.id = this.options.error_block;
					error_block.addClassName("error");
					$(this.options.content_wrapper).insert({"top": error_block});
				}
				$(this.options.error_block).update("<li>"+transport.responseText.evalJSON().join("</li><li>")+"</li>");
				Element.scrollTo($(this.options.error_block));
				//alert(msg);
				this.reset();
			}.bind(this),
			onFailure: function(transport) {
				alert("We're sorry, but there has been an error on our server. The webmaster has been notified and the problem will be rectified as soon as possible. Please try again later.");
				this.reset();
			}.bind(this)
		});		
	},
	_handleDistances: function(distances) {
		if(distances === false) {
			this.has_location = false;
			var msg = "";
			msg += "<strong class=\"error\">We're sorry, but we couldn't find your location.</strong>\n";
			msg += "In order to sort these results by distance, <strong>please try entering your location again</strong>.\n";
			msg += "Entering your <strong>postal code</strong> is the most reliable means of generating a successful search.\n\n";
			msg += "Your search results (sorted by keyword relevance) are displayed below.\n";
			this.feedback = msg;
			this.getResults(); // just get the results without location sorting
		} else {
			this.getResults(distances);
		}
	},
	displayForm: function() {
		this.update(this.search_form_content);
		this.reset();
	},
	update: function(content) {
		//content = content.evalHTML();
		if(this.feedback != null) {
			content.insert({"top": new Element("p").update(this.feedback.nl2br())});
		}
		var el = $(this.options.main_container);
		el.update(content);
		Element.scrollTo(el);
	},
	writeStatus: function(message) {
		$(this.options.search_button).value = message;
	},
	disableForm: function() {
		$(this.search_form).descendants().each(function(el) {
			if(el.tagName.toLowerCase() == "input") {
				el.disabled = true;
			}
		}, this);
	},
	enableForm: function() {
		$(this.search_form).descendants().each(function(el) {
			if(el.tagName.toLowerCase() == "input") {
				el.disabled = false;
			}
		}, this);		
	}
}

Event.observe(window, 'load', function() { var search = new Search(); });
