function Geodistancer() {}
Geodistancer.prototype = {
	geolocator: new Geolocator(),
	search_params: null,
	geodata: null,
	geolocate_retried: false,
	reset: function() {
		this.geolocate_retried = false;
		this.search_params = null;
		this.geodata = null;
	},
	/**
	 * Calculate distances from search parameters
	 * 
	 * @param (Hash) search_params
	 * @param (Hash) geodata
	 */
	getDistances: function(search_params, geodata, callback) {
		// save the input parameters in the object
		this.search_params = search_params;
		this.geodata = geodata;
		this.callback = callback;
		// decide which type of geolocate to perform
		var type;
		if(this.geolocator.hasFull(search_params)) {
			type = this.geolocator.type.full;		
		} else if (this.geolocator.hasAddress(search_params)) {
			type = this.geolocator.type.address;
		} else if (this.geolocator.hasPostalCode(search_params)) {
			type = this.geolocator.type.postal_code;
		} else if (this.geolocator.hasTown(search_params)) {
			type = this.geolocator.type.town;
		} else {
			throw "Invalid Parameters";
		}		
		// fork to geolocator
		this._geolocate(type);
	},
	hasLocation: function(params) {
		var hash = $H(params);
		return this.geolocator.hasPostalCode(hash) || this.geolocator.hasTown(hash);
	},
	_geolocate: function(type) {
		this.geolocator.locate(this.search_params, this._dispatchResponse.bind(this, type), type);		
	},
	_dispatchResponse: function(type, response) {
		if (response.Status.code == "200") 
		{
			var client_geodata = response;
			this._doSort(client_geodata);
		} 
		else if(	(response.Status.code == "602" || response.Status.code == "601") && 
					!this.geolocate_retried &&
					type == this.geolocator.type.postal_code &&
					this.geolocator.hasPostalCode(this.search_params))
		{			
			this.geolocate_retried = true; // about to retry with just the postal code, so let's track that
			this._geolocate(this.geolocator.type.postal_code);
			return;
		} 
		else 
		{
			this._respond(false); // we didn't successfully accomplish anything	
		}		
	},
	_doSort: function(client_geodata) {		
		var distances = new Hash();
		var client_lat = client_geodata.Placemark[0].Point.coordinates[1];
		var client_lon = client_geodata.Placemark[0].Point.coordinates[0];
		this.geodata.each(function(pair) {
			var id = pair.key;
			var gd = pair.value.evalJSON();
			var gd_lat = gd.Placemark[0].Point.coordinates[1];
			var gd_lon = gd.Placemark[0].Point.coordinates[0];
			distances.set(id, this._calculateDistance(client_lat, client_lon, gd_lat, gd_lon));
		}, this);
		this._respond(distances);
	},
	_respond: function(response) {
		this.reset();
		this.callback(response);
	},
	_calculateDistance: function(lat1, lon1, lat2, lon2) {
		var R = 6371; // km
		var dLat = (lat2-lat1).toRad();
		var dLon = (lon2-lon1).toRad(); 
		var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) * Math.sin(dLon/2) * Math.sin(dLon/2); 
		var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
		var d = R * c;
		return d;
	}	
}
