/**
* @name HiveGeocoder Google
* @version 0.9.0
* @author Joe Johnston <joe@socialhive.org>
* @copyright (c) 2009 Joe Johnston
* http://socialhive.org/hivemaps
* http://code.google.com/p/hivemaps
*
* Creates SOCIALHIVE.geo.geocoder
*
**/

/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/

(function($){  
	var HiveGeocoder = {
		geocoder: null,
		geocodeAccuracy: ['Unknown', 'Country', 'Region', 'Sub-region', 'Town', 'Post code', 'Street', 'Intersection', 'Address'],
		geocodeAccuracyZoom: [2, 5, 6, 7, 10, 11, 12, 13, 14],
		geocodeMessages: {
			en: {
				200 /*G_GEO_SUCCESS*/: 'Success',
				601 /*G_GEO_MISSING_ADDRESS, G_GEO_MISSING_QUERY*/: 'Missing Address: The address was either missing or had no value.',
				602 /*G_GEO_UNKNOWN_ADDRESS*/: 'Sorry ... we could not find the address.  Try another search.',
				603 /*G_GEO_UNAVAILABLE_ADDRESS*/: 'Unavailable Address:  The geocode for the given address cannot be returned due to legal or contractual reasons.',
				604 /*G_GEO_UNKNOWN_DIRECTIONS*/: 'Unable to find directions.',
				610 /*G_GEO_BAD_KEY*/: 'Bad Key: The API key is either invalid or does not match the domain for which it was given',
				620 /*G_GEO_TOO_MANY_QUERIES*/: 'Too Many Queries: The daily geocoding quota for this site has been exceeded.',
				500 /*G_GEO_SERVER_ERROR*/: 'Server error: The geocoding request could not be successfully processed.',
				400 /*G_GEO_BAD_REQUEST*/: 'Oops! ... An error occurred.  Please reload this page and try again.'
			}
		},
		getLatLng: function(address, f) {
			this.geocoder.getLatLng(address, f);
		},
		getLocations: function(address, f) {
			this.geocoder.getLocations(address, f);
		},
		getZoomFromResult: function(result) {
			return this.geocodeAccuracyZoom[result.Placemark[0].AddressDetails.Accuracy];
		},
		getErrorMessage: function(result) {
			return (this.geocodeMessages.en[result.Status.code]) ? this.geocodeMessages.en[result.Status.code] : this.geocodeMessages.en[400];
		},
		/**
		* Find the closest point in getLocations results to lat,lon.
		**/
		getNearestResult: function(results, lat, lon) {
			var nearest = {distance: 999999999, result: null};
			for (var i=0; i<results.Placemark.length; i++) {
				var d = SOCIALHIVE.geo.distance(results.Placemark[i].Point.coordinates[1], results.Placemark[i].Point.coordinates[0], lat, lon);
				if (d < nearest.distance) {
					nearest.distance = d;
					nearest.result = results.Placemark[i];
				}
			}
			return nearest;
		},
		/**
		* Get street, city, state, zip, and country from address returned from getLocations.
		*
		* This code has not been significantly tested for all areas around the world, but it seems to do a pretty
		* good job of extracting out city and state/province/region.
		*
		* param address is normally geocoder result.AddressDetails object
		**/
		getAddressFromDetails: function(address) {
			var results = {};
			var get = SOCIALHIVE.utils.searchObjProp;
			results.country_code = get(address, 'Country.CountryNameCode', '');
			results.country = get(address, 'Country.CountryName', '');
			results.state = get(address, 'Country.AdministrativeArea.AdministrativeAreaName', '');
			if (!results.state && get(address, 'Country.AdministrativeArea.SubAdministrativeArea.Locality')) 
				results.state = get(address, 'Country.AdministrativeArea.SubAdministrativeArea.SubAdministrativeAreaName', '');
			var sub = (get(address, 'Country.AdministrativeArea.SubAdministrativeArea')) ? 'SubAdministrativeArea.' : '';	
			results.city = get(address, ['Country.AdministrativeArea.'+sub+'Locality.DependentLocality.DependentLocalityName', 'Country.AdministrativeArea.'+sub+'Locality.LocalityName', 'Country.AdministrativeArea.'+sub+'SubAdministrativeAreaName', 'Country.Locality.LocalityName'], '');
			results.zip = get(address, ['Country.AdministrativeArea.'+sub+'Locality.PostalCode.PostalCodeNumber', 'Country.AdministrativeArea.'+sub+'PostalCode.PostalCodeNumber'], '');
			results.street = get(address, ['Country.AdministrativeArea.'+sub+'Locality.DependentLocality.DependentLocalityName', 'Country.AdministrativeArea.'+sub+'Locality.Thoroughfare.ThoroughfareName', 'Country.AdministrativeArea.'+sub+'Thoroughfare.ThoroughfareName'], '');
			// handle sub-region mismatch; e.g. Indianapolis, IN, USA
			if (results.street == results.city) results.street = '';
			return results;
		}
	};
  
  // init
  jQuery(function($) {
		HiveGeocoder.geocoder = new GClientGeocoder();
  });

  if (!window.SOCIALHIVE)
    window.SOCIALHIVE = {};
  if (!window.SOCIALHIVE.geo)
    window.SOCIALHIVE.geo = {};
  window.SOCIALHIVE.geo.geocoder = HiveGeocoder;
})(jQuery);

