var google_maps =  function(id, opts) { 
	if(this.initialize){ this.initialize(id, opts);}
	return this;
};

google_maps.prototype = {
	
	map: 0,
	yellowicon: 0,
	redicon:0,
	large_map:true,
	controls:true,
	zoom_only:true,
	start_point: new GLatLng(37, -122),
	start_zoom:10,
	map_type:G_HYBRID_MAP,
	id: 0,
	_addr_url: "/location/addrinfo/",
	_zipaddr_url: "/location/ziploc/",
	_zipaddr_url2: "/location/ziploc2/",
	_latlngaddr_url: "/location/fromcoord/",
	_markers:[],
	_d_cache: {},
	_requested:{},
	city:null,
	country:null,
	province: null,
	found_addr_zoom: 7,
	post_get_address: function(a,b,c){},
	
	_last_loc_c: null,
	
	initialize: function(id, opts) 
	{
		if (!GBrowserIsCompatible())  return;
		this.id = id;
		this.map = new GMap2($(id));
		if(opts){
			this.found_addr_zoom = opts.found_addr_zoom || 7;
			this.country = opts.country || null;
			this.city = opts.city || null;
			this.province = opts.province || null;
			this.large_map = typeof opts.large_map != 'undefined' ? opts.large_map : true;
			this.controls = typeof opts.controls != 'undefined' ? opts.controls : true;
			this.zoom_only = typeof opts.zoom_only != 'undefined' ? opts.zoom_only : true;
			this.start_point = opts.start_point || new GLatLng(39, -101);
			 //new GPoint(-122, 37);
			this.start_zoom = opts.start_zoom || 10;
			this.map_type = opts.map_type || G_HYBRID_MAP;
			this.add_start_marker = typeof opts.add_start_marker != 'undefined' ? opts.add_start_marker : true;
			this.post_get_address = opts.post_get_address || function(a,b,c){};
		}
		
		if(this.large_map && this.controls){
			this.map.addControl(new GLargeMapControl());
			this.map.addControl(new GMapTypeControl());
		}else if(!this.large_map && this.controls){
			this.map.removeControl(new GLargeMapControl());
			this.map.removeControl(new GMapTypeControl());
			
			if(!this.zoom_only){
				this.map.addControl(new GSmallMapControl());
			}else{
				this.map.addControl(new GSmallZoomControl());
			}
		}
		//this.map.centerAndZoom(this.start_point, this.start_zoom);
		//this.map.setMapType(this.map_type);
		this.map.setCenter(this.start_point, this.start_zoom, this.map_type);
		if(this.add_start_marker){
			this.current_marker = new GMarker(this.start_point);
			this.getMap().addOverlay(this.current_marker);
		}
		
		if(opts.add_click_listener){
			GEvent.addListener(this.map, 'click', opts.add_click_listener)
		}
		
		this.redicon = new GIcon();
		this.redicon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
		this.redicon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
		this.redicon.iconSize = new GSize(12, 20);
		this.redicon.shadowSize = new GSize(22, 20);
		this.redicon.iconAnchor = new GPoint(6, 20);
		this.redicon.infoWindowAnchor = new GPoint(5, 1);

		this.yellowicon = new GIcon();
		this.yellowicon.image = "http://labs.google.com/ridefinder/images/mm_20_yellow.png";
		this.yellowicon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
		this.yellowicon.iconSize = new GSize(12, 20);
		this.yellowicon.shadowSize = new GSize(22, 20);
		this.yellowicon.iconAnchor = new GPoint(6, 20);
		this.yellowicon.infoWindowAnchor = new GPoint(5, 1);
	},
	
	getMap: function()
	{
		return this.map;
	},
	getAddressEvent: function(e, addr){
		this.getAddress(addr);
	},
	
	getAddressFromLatLong: function(lat, lng, nomove){
		lat = parseFloat(lat);
		lng = parseFloat(lng);
		if(!lat || !lng){ return; }
		var k = lat + "_" + lng;
		if(this._d_cache[k]){
			populate(this, this._d_cache[k]);
		} 
		if(this._requested[k]){ return; }
		this._requested[k] = k;
		function populate(obj, info){
			if(!info){
				obj.post_get_address(obj, info, 'no');
				return false;
			}
			var gotD =false;
			//geonames.org
			var lat,lng, city, prov, ctry;
			if(info.geonames && info.geonames.length){
				pcode = info.geonames[0]
				if(pcode.lng && pcode.lat){
					lat = pcode.lat;
					lng = pcode.lng;
				}
				if(pcode.adminName2){
					city = pcode.adminName2;
				}
				if(pcode.name){
					city = pcode.name;
				}
				if(pcode.adminCode1){
					prov = pcode.adminCode1;
				}
				if(pcode.adminName1){
					prov = pcode.adminName1;
				}
				if(pcode.countryCode){
					ctry = pcode.countryCode;
				}
				if(ctry && city && !prov){
					prov = ' '; //sometimes there is no prov
				}
				//remove the 'State of...'
				prov = prov.replace("State of ", "");

			}
			
			if(lat && lng && !nomove){
				obj.updateMapPoint(lat, lng, this.found_addr_zoom);
			}
			if(prov){
				if(typeof(obj.province) == typeof({})){
					obj.province.value = prov;
				}else{
					obj.province = prov;
				}
				gotD = true;
			}
			if(ctry){
				if(typeof(obj.country) == typeof({})){
					obj.country.value = ctry;
				}else{
					obj.country = ctry;
				}
				gotD = true;
			}
			if(city){
				if(typeof(obj.city) == typeof({})){
					obj.city.value = city;
				}else{
					obj.city = city;
				}
				gotD = true;
			}
			obj.post_get_address(obj, info, gotD?'ok':'no');
			return gotD;
		}
		
		function happy(o){
			var gm = (o.argument[0])?o.argument[0]:null;
			var key = (o.argument[1])?o.argument[1]:null;
			if(o.responseText){
				try{
					eval ( "var info = " + o.responseText);
				}catch(e){return;}
				if(key && info){
					gm._d_cache[key] = info;
				}
				populate(gm, info);
			}
		}
		
		var callback = { success:happy, failure: void(0), timeout: Organizer.timeOutTime, argument:[this, k]};
		lat = Math.floor(lat * 1000) / 1000;
		lng = Math.floor(lng * 1000) / 1000;
		
		var sUrl = this._latlngaddr_url +"?lat=" +escape(lat) + "&lng=" + escape(lng);
		var request = Organizer.connect.asyncRequest('GET', sUrl, callback, "");	
	},
	googleToPcode: function (info){
		var lat, lng, city, prov, ctry;
		if(info.Point){
			lat = info.Point.coordinates[1];
			lng = info.Point.coordinates[0];
		}
		var onAddr = info.AddressDetails.Country || null;
		if(onAddr){
			try{
				if(onAddr.AdministrativeArea){
					prov = onAddr.AdministrativeArea.AdministrativeAreaName;
					//remove the 'State of...'
					prov = prov.replace("State of ", "");
				}
			}catch(e){};
			try{
				if(onAddr.CountryNameCode){
					ctry = onAddr.CountryNameCode;
				}
			}catch(e){}
			try{
				if(onAddr.AdministrativeArea.SubAdministrativeArea && onAddr.AdministrativeArea.SubAdministrativeArea.Locality){
					city = onAddr.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName;
				}
				if(onAddr.AdministrativeArea.Locality){
					city = onAddr.AdministrativeArea.Locality.LocalityName;
				}
			}catch(e){}
		}
		return  {'placeName': city, 'countryCode': ctry, 'adminName1': prov, 'lat' : lat, 'lng': lng};
	},
	populate: function(obj, info){
		if(!info){  
			obj.post_get_address(obj, info, 'no');
			return false;
		}
		var lat,lng, city, prov, ctry = '';
		try{
			if(info.Placemark){
				info = obj.googleToPcode(info.Placemark[0]);
			}
		}catch(e){}
		try{
			if(info.Point.coordinates){
				info = obj.googleToPcode(info);
			}
		}catch(e){}
		pcode = (info.postalCodes && info.postalCodes.length)?info.postalCodes[0]:info;
		if(pcode.lng){
			if(pcode.lng && pcode.lat){
				lat = pcode.lat;
				lng = pcode.lng;
			}
			if(pcode.placeName){
				city = pcode.placeName;
			}
			if(pcode.adminCode1){
				prov = pcode.adminCode1;
			}
			if(pcode.adminName1){
				prov = pcode.adminName1;
			}
			if(pcode.countryCode){
				ctry = pcode.countryCode;
			}
			if(ctry && city && !prov){
				prov = ' '; //sometimes there is no prov
			}
			//remove the 'State of...'
			prov = prov?prov.replace("State of ", ""):'';
		}
				
		if(lat && lng){
			obj.updateMapPoint(lat, lng, this.found_addr_zoom);
		}
		if(prov){
			if(typeof(obj.province) == typeof({})){
				obj.province.value = prov;
			}else{
				obj.province = prov;
			}
		}
		if(ctry){
			if(typeof(obj.country) == typeof({})){
				obj.country.value = ctry;
			}else{
				obj.country = ctry;
			}
		}
		if(city){
			if(typeof(obj.city) == typeof({})){
				obj.city.value = city;
			}else{
				obj.city = city;
			}
		}
		obj.post_get_address(obj, info, 'ok');
	},
	getFullAddress: function(addr, zip){
		if(!addr.strip().length){ 
			return this.getAddress(zip, true); 
		}
		addr = zip.strip()?addr + " " + zip:addr;
		var geocoder = new GClientGeocoder();
		var gm = this;
		function getProperCode(pcodes){
			//if more then one, and doModal need to ask which one
			if(pcodes && pcodes.length > 1){
				var d = $newDiv('loc_choose', document.body);
				Organizer.matchSize(gm.id, d);
				d.ongm = gm;
				d.kk = addr;
				var tpl = '<input type="radio" onclick="var c=$(\'loc_choose\'); c.ongm.populate(c.ongm,c.ongm._d_cache[c.kk].Placemark[{i}]);Organizer.remove(c);" /> {loc} <br />';
				var st = "<h3>Multiple Locations were Found</h3>";
				st += "<h3>Please Choose the Proper Location.</h3>";
				st += '<a href="javascript:void(0)" onclick="var c=$(\'loc_choose\'); c.ongm.post_get_address(c.ongm); Organizer.remove(c)" title="close" class="bubble_close"> </a>';
				for(var i=0;i < pcodes.length;i++){
					var on = gm.googleToPcode(pcodes[i]);
					var cty = on.placeName?on.placeName:"(n/a)";
					var prv = on.adminName1?on.adminName1:"(n/a)";
					var loc = cty + " - " + prv + " <strong>" + on.countryCode + "</strong>";
					st += tpl.replace("{i}", i).replace('{loc}', loc);
					d.innerHTML = st;
				}
				d.innerHTML += '<input type="radio" onclick="var c=$(\'loc_choose\'); c.ongm.post_get_address(c.ongm); Organizer.remove(c)" /> <strong>It\'s not here, I\'ll try again.</strong> <br />';

			}else if(pcodes && pcodes.length == 1){
				return gm.populate(gm, pcodes[0]);
			}else{
				gm.post_get_address(gm, pcodes, 'no');
			}
		}
		function massage(res){
			if (!res || res.Status.code != 200) {
				gm.post_get_address(gm, {}, 'no');
			} else {
				gm._d_cache[addr] = res;
				getProperCode(res.Placemark)
			}
		}
		geocoder.getLocations(addr, massage);
	},
	getAddress: function(formele, izzip){
		addr = formele;
		if(formele.value){
			addr = formele.value;
		}
		var on_obj = this;
		if(izzip && (addr.length < 4 && addr.match('/^\d/'))){
			on_obj.post_get_address(on_obj, {}, 'no');
			return false;
		}
		if(addr.length < 3){
			on_obj.post_get_address(on_obj, {}, 'no');
			return; 
		}
		if(typeof addr == typeof({}) || addr.length == 0){ return;}
		function getProperCode(pcodes){
			//if more then one, and doModal need to ask which one
			if(pcodes && pcodes.length > 1){
				var d = $newDiv('loc_choose', document.body);
				Organizer.matchSize(on_obj.id, d);
				d.ongm = on_obj;
				d.kk = addr;
				var tpl = '<input type="radio" onclick="var c=$(\'loc_choose\'); c.ongm.populate(c.ongm,c.ongm._d_cache[c.kk].postalCodes[{i}]);Organizer.remove(c);" /> {loc} <br />';
				var st = "<h3>Multiple Locations were Found</h3>";
				st += "<h3>Please Choose the Proper Location.</h3>";
				st += '<a href="javascript:void(0)" onclick="var c=$(\'loc_choose\'); c.ongm.post_get_address(); Organizer.remove(c)" title="close" class="bubble_close"> </a>';
				for(var i=0;i < pcodes.length;i++){
					var on = pcodes[i];
					var loc = on.placeName + " - <strong>" + on.countryCode + "</strong> [" + on.postalCode + "]";
					st += tpl.replace("{i}", i).replace('{loc}', loc);
					d.innerHTML = st;
				}
				d.innerHTML += '<input type="radio" onclick="var c=$(\'loc_choose\'); c.ongm.post_get_address(c.ongm); Organizer.remove(c)" /> <strong>It\'s not here, I\'ll try again.</strong> <br />';

			}else if(pcodes && pcodes.length == 1){
				return on_obj.populate(on_obj, pcodes[0]);
			}else{
				on_obj.post_get_address(on_obj, pcodes, 'no');
			}
		}
		if(this._d_cache[addr] && this._d_cache[addr].postalCodes){
			return getProperCode(this._d_cache[addr].postalCodes);
		} 
		if(this._requested[addr]){ return; }
		this._requested[addr] = addr;
		function happy(o){
			var gm = (o.argument[0])?o.argument[0]:null;
			var key = (o.argument[1])?o.argument[1]:null;
			var durl = (o.argument[2])?o.argument[2]:null;
			
			if(o.responseText){
				try{
					eval ( "var info = " + o.responseText);
				}catch(e){ getProperCode({}); }
				if(info && info.postalCodes && info.postalCodes.length == 0 && durl && !durl.match('ziploc2') && izzip){
					var sUrl = gm._zipaddr_url2  +"?zip=" +escape(addr);
					var callback = { success:happy, failure: void(0), timeout: Organizer.timeOutTime, argument:[gm, addr, sUrl]};
					var request = Organizer.connect.asyncRequest('GET', sUrl, callback, "");	
					return;
				}
				if(key){
					gm._d_cache[key] = info;
				}
				if(info.postalCodes){ getProperCode(info.postalCodes); }
			}
		}
		var sUrl = this._addr_url +"?q=" +escape(addr);
		if(izzip){
			sUrl = this._zipaddr_url +"?zip=" +escape(addr);
		}
		
		var callback = { success:happy, failure: void(0), timeout: Organizer.timeOutTime, argument:[this, addr, sUrl]};
		var request = Organizer.connect.asyncRequest('GET', sUrl, callback, "");	
	},
	
	'addMarker': function(llat, llong)
	{
		var k = llat + "|" + llong;
		if(this._markers[k]) return false;
		this._markers[k] = new GLatLng(llat, llong);
		this.getMap().addOverlay(this._markers[k]);
		return this._markers[k];
	},
	
	dectodms: function(dec) 
	{
		// Splitting avoids floating point bad times
		dec = dec + '.0'; // Cheesy string conversion
		var dataset;
		if (dec) {
			var parts = dec.split('.');
			var degrees = parts[0];
			var temp = eval("0." + parts[1]);
			temp = temp * 60;
			var minutes = Math.floor(temp);
			var seconds = (temp*60) - (minutes*60);
			
			dataset = new Array();
			dataset[0] = degrees;
			dataset[1] = minutes;
			dataset[2] = seconds;
		} else {
			dataset = new Array();
			dataset[0] = 0;
			dataset[1] = 0;
			dataset[2] = 0;
			return dataset;
		}
		return dataset;
	},

	dmstodec: function(degrees, minutes, seconds) {
		var dec = parseFloat(Math.abs(degrees));
		dec += parseFloat(minutes)/60;
		dec += parseFloat(seconds)/3600;
		if (degrees < 0) {
			dec = eval('-' + dec);
		}
		return dec;
	},
	
		
	updateLatLongFields: function(lat, log) {
		var dmslat = this.dectodms(lat);			
		var dmslon = this.dectodms(log);
		if(!$('geo_lat')){ return; }
		$('geo_lat').value = lat;
		$('geo_long').value = log;
		$('tmp_lat_deg').value = dmslat[0];
		$('tmp_lat_min').value = dmslat[1];
		$('tmp_lat_sec').value = dmslat[2];
		var gm = this;
		$('tmp_lat_deg').onblur = function() {gm.updateMapPoint();};
		$('tmp_lat_min').onblur = function() {gm.updateMapPoint();};
		$('tmp_lat_sec').onblur = function() {gm.updateMapPoint();};
		$('tmp_lon_deg').value = dmslon[0];
		$('tmp_lon_min').value = dmslon[1];
		$('tmp_lon_sec').value = dmslon[2];
		$('tmp_lon_deg').onblur = function() {gm.updateMapPoint();};
		$('tmp_lon_min').onblur = function() {gm.updateMapPoint();};
		$('tmp_lon_sec').onblur = function() {gm.updateMapPoint();};
	},

	updateMapPoint: function(ilat, ilong, zoom) {
		var lat = ilat || this.dmstodec($('tmp_lat_deg').value,$('tmp_lat_min').value, $('tmp_lat_sec').value);
		var lng = ilong || this.dmstodec($('tmp_lon_deg').value, $('tmp_lon_min').value, $('tmp_lon_sec').value);
		if (this.current_marker) {
			this.getMap().removeOverlay(this.current_marker);
		}
		//var point = new GPoint(lng, lat);
		var point = new GLatLng(lat, lng);

		this.current_marker = new GMarker(point);
		this.getMap().addOverlay(this.current_marker);
		if(zoom){
			this.getMap().setCenter(point, zoom);
		}else{
			this.getMap().setCenter(point);
		}
		//updateLatLongFields(point.y, point.x);
		this.updateLatLongFields(point.lat(), point.lng());
	}
};
