// Include google maps api first
var MyGeocoder = MyGeocoder ? MyGeocoder : function() {
	// private properties and methods
	var geocoder = new GClientGeocoder();
	
	// Calls itself iteratively until it finds a result, each time diminishing the amount of details
	// of the query
	function searchiteration(street, zipcode, city, state, country, callback, nbiteration){
		var searchtxt = street + ' ' + zipcode + ' ' + city + ' ' + state + ' ' + country;
		// Eliminate double spaces
		while(searchtxt.indexOf('  ') > -1){
			searchtxt = searchtxt.replace('  ', ' ');
		}
		
		geocoder.getLocations(searchtxt, function(location){
					var o = location;
					if (o.Status.code == 200){
						if (o.Placemark){
							callback(o);
							return;
						}
					}
					
					if (nbiteration == 0){
						searchiteration('', zipcode, city, state, country, callback, 1);
					}else if (nbiteration == 1){
						searchiteration('', '', city, state, country, callback, 2);
					}else if (nbiteration == 2){
						searchiteration('', '', '', state, country, callback, 2);
					}else if (nbiteration == 3){
						searchiteration('', '', '', '', country, callback, 3);
					}else {
						callback(o);
					}
			}
		);
	};
	
	// Show nested object properties
	function objectToString(a){
		var s = '';
		for(var p in a){
			if (a[p].constructor == Object){
				s += p + '{\n'+ objectToString(a[p]) + '}\n';
			}else{
		  	s += p + ' : ' + a[p] + '\n';
		  }
		}
		return s;
	};
	
	// ----------------------------------------------------------
	// public methods
	return {
	
		searchAddress : function(address, callback, countryCode) {
			if (!countryCode){
				geocoder.setBaseCountryCode('none');
			}else{
				geocoder.setBaseCountryCode(countryCode);
			}
			geocoder.getLocations(address, callback);
		},
		
		searchLatLng : function(address, callback, countryCode) {
			if (!countryCode){
				geocoder.setBaseCountryCode('none');
			}else{
				geocoder.setBaseCountryCode(countryCode);
			}
			geocoder.getLatLng(address, callback);
		},
		
		searchIteratively : function(street, zipcode, city, state, country, callback, countryCode) {
			if (!countryCode){
				geocoder.setBaseCountryCode('none');
			}else{
				geocoder.setBaseCountryCode(countryCode);
			}
			searchiteration(street, zipcode, city, state, country, callback, 0);
		},
		
		getAccuracy : function(GGeoAddressAccuracy) {
			switch(GGeoAddressAccuracy){
				case 0 : return 'Unknown location';
				case 1 : return 'Country level accuracy';
				case 2 : return 'Region (state, province, prefecture, etc.) level accuracy';
				case 3 : return 'Sub-region (county, municipality, etc.) level accuracy';
				case 4 : return 'Town (city, village) level accuracy';
				case 5 : return 'Post code (zip code) level accuracy';
				case 6 : return 'Street level accuracy';
				case 7 : return 'Intersection level accuracy';
				case 8 : return 'Address level accuracy';
				case 9 : return 'Premise (building name, property name, shopping center, etc.) level accuracy';
			}
		},
		
		getStatus : function(GGeoStatusCode) {
			switch(GGeoStatusCode){
				case 200 : return 'Success';
				case 400 : return 'Bad request';
				case 500 : return 'Server error';
				case 601 : return 'Missing query';
				case 602 : return 'Unknown address';
				case 603 : return 'Unavailable address';
				case 604 : return 'Unknown directions';
				case 610 : return 'Bad key';
				case 620 : return 'Too many queries';
			}
		},
		
		LocationToString : function(location){
			var nl = '\n';
			var o = location;
			var s = 'name: ' + o.name + nl;
			s = s + 'Status code: ' + o.Status.code + ' - ' + this.getStatus(o.Status.code) + nl;
			if (o.Status.code == 200){
				if (o.Placemark){
					for (var i = 0; i < o.Placemark.length; i++){
						s = s + nl + 'Placemark ' + (i+1) + ' of ' + o.Placemark.length + ':' + nl;
						var pm = o.Placemark[i];
						s = s + '-> address: ' + pm.address + nl;
						s = s + '-> Accuracy: ' + pm.AddressDetails.Accuracy + ' - ' + this.getAccuracy(pm.AddressDetails.Accuracy) + nl;
						var coord = pm.Point.coordinates;
						s = s + '-> coordinates: ' + coord[0] +', ' + coord[1] + nl;
					}
				}
			}
			return s;
		},
		
		PlacemarkToString : function(placemark){
			var nl = '\n';
		    var pm = placemark;
		    var s = pm.address + nl;
		    s = s + 'Accuracy: ' + pm.AddressDetails.Accuracy + ' - ' + this.getAccuracy(pm.AddressDetails.Accuracy) + nl;
		    return s;
		}
		
	};
}();