//Loads the API information from Google's servers
google.load("maps","2.x");
var map;
var geoCoder;
var marker;
var searchString;
var reasons = [];
var dirReasons = [];
var dir;
var html = [];
var revCoder;
var urlZoom = null;

//This is the code that creates the google map
function initializeMap(lat,lng,zoom)
{
	//The variable that holds the map itself
	map = new google.maps.Map2($("mapDiv"));
	map.setCenter(new google.maps.LatLng(44.3701126607613, -64.5238208770752),zoom);
	
	//Set up the map's options & controls
	//Default to Hybrid map
	map.setMapType(G_HYBRID_MAP);
	map.enableScrollWheelZoom();
	//Sets up the normal map type structure, then removes the dropdown (can cause problems)
	var mapTypes = new google.maps.HierarchicalMapTypeControl();
	mapTypes.clearRelationships();
	map.addControl(mapTypes);
	//Creates the navigation controls
	map.addControl(new google.maps.SmallMapControl());
	
	//Creates the Google Geolocator class for address translation
	geoCoder = new google.maps.ClientGeocoder();
	
	//Creates the marker
	marker = new google.maps.Marker(new google.maps.LatLng(lat,lng),{draggable:true});
	map.addOverlay(marker);
	marker.hide();
	
	//Creates the GDirections object
	dir = new google.maps.Directions(map,$('dirBoxInt'));
	
	//Creates the GReverseGeocoder object
	revCoder = new GReverseGeocoder(map);
	
	//Creates the info window html's
	html[0] = "<div style='text-align:left;'>Directions:<br /><a href='javascript:toWindow()'>To Here</a>&nbsp;-&nbsp;<a href='javascript:fromWindow()'>From Here</a></div>";
	html[1] = "<div style='text-align:left;'>Directions:<br /><strong>To Here</strong>&nbsp;-&nbsp;<a href='javascript:fromWindow()'>From Here</a>"
		+ "<br />Starting Address:<br /><form action='javascript:revCoder.reverseGeocode(marker.getLatLng());'><input type='text' name='dirAddr' id='dirAddr' value='' /><br />"
		+ "<input type='submit' value='Get Directions' /><br />Walk&nbsp;<input type='checkbox' name='walk' id='walk' />&nbsp;&nbsp;Avoid Highways"
		+ "&nbsp;<input type='checkbox' name='highways' id='highways' /><input type='hidden' name='type' id='type' value='to' /></form></div>";
	html[2] = "<div style='text-align:left;'>Directions:<br /><a href='javascript:toWindow'>To Here</a>&nbsp;-&nbsp;<strong>From Here</strong>"
		+ "<br />End Address:<br /><form action='javascript:revCoder.reverseGeocode(marker.getLatLng());'><input type='text' name='dirAddr' id='dirAddr' value='' /><br />"
		+ "<input type='submit' value='Get Directions' /><br />Walk&nbsp;<input type='checkbox' name='walk' id='walk' />&nbsp;&nbsp;Avoid Highways"
		+ "&nbsp;<input type='checkbox' name='highways' id='highways' /><input type='hidden' name='type' id='type' value='from' /></form></div>";
	
	//Creates the drag end event (when finished dragging the marker)
	google.maps.Event.addListener(marker,'dragend',getLatLng);
	//Creates the right click event
	google.maps.Event.addListener(map,'singlerightclick',addMarker);
	//Creates the click event that opens the marker window
	google.maps.Event.addListener(marker,'click',function(){marker.openInfoWindowHtml(html[0])});
	//Creates event to catch errors with direction finding
	google.maps.Event.addListener(dir,'error',function()
			{
				var code = dir.getStatus().code;
				var reason = "Code: " + code;
				if(dirReasons[code])
				{
					reason = dirReasons[code];
				}
				alert("Failed to get directions, " + reason);
			});
	//Creates an event for successful reverse geocoding
	google.maps.Event.addListener(revCoder,'load',getDirections);
	
	//Array for decoding the failure codes
	reasons[G_GEO_SUCCESS]            = "Success";
	reasons[G_GEO_MISSING_ADDRESS]    = "Missing Address: The address was either missing or had no value.";
	reasons[G_GEO_UNKNOWN_ADDRESS]    = "Unknown Address:  No corresponding geographic location could be found for the specified address.";
	reasons[G_GEO_UNAVAILABLE_ADDRESS]= "Unavailable Address:  The geocode for the given address cannot be returned due to legal or contractual reasons.";
	reasons[G_GEO_BAD_KEY]            = "Bad Key: The API key is either invalid or does not match the domain for which it was given";
	reasons[G_GEO_TOO_MANY_QUERIES]   = "Too Many Queries: The daily geocoding quota for this site has been exceeded.";
	reasons[G_GEO_SERVER_ERROR]       = "Server error: The geocoding request could not be successfully processed.";
	
	//Array for decoding the direction failure codes
	dirReasons[G_GEO_SUCCESS]            = "Success";
	dirReasons[G_GEO_MISSING_ADDRESS]    = "Missing Address: The address was either missing or had no value.";
	dirReasons[G_GEO_UNKNOWN_ADDRESS]    = "Unknown Address:  No corresponding geographic location could be found for the specified address.";
	dirReasons[G_GEO_UNAVAILABLE_ADDRESS]= "Unavailable Address:  The geocode for the given address cannot be returned due to legal or contractual reasons.";
	dirReasons[G_GEO_BAD_KEY]            = "Bad Key: The API key is either invalid or does not match the domain for which it was given";
	dirReasons[G_GEO_TOO_MANY_QUERIES]   = "Too Many Queries: The daily geocoding quota for this site has been exceeded.";
	dirReasons[G_GEO_SERVER_ERROR]       = "Server error: The geocoding request could not be successfully processed.";
	dirReasons[G_GEO_BAD_REQUEST]        = "A directions request could not be successfully parsed.";
	dirReasons[G_GEO_MISSING_QUERY]      = "No query was specified in the input.";
	dirReasons[G_GEO_UNKNOWN_DIRECTIONS] = "The GDirections object could not compute directions between the points.";
}

//Function that opens up the 'to here' form in the bubble
function toWindow()
{
	marker.openInfoWindowHtml(html[1]);
}

//Function that opens up the 'from here' form in the bubble
function fromWindow()
{
	marker.openInfoWindowHtml(html[2]);
}

//Gets the current latitude and longitude of the marker and puts them in the textboxes
function getLatLng()
{
	$('latitude').value = marker.getLatLng().lat();
	$('longitude').value = marker.getLatLng().lng();
}

//Geocodes an address into a usable latitude and longitude
function geoCodeAddress(form, zoom)
{
	var addr = "", city = "", state = "", postal = "", country = "";
	urlZoom = zoom;
	if(form.address.value != "Address")
	{
		addr = form.address.value;
	}
	if(form.city.value != "Town/City")
	{
		city = form.city.value;
	}
	if(form.province.value != "Province/State")
	{
		state = form.province.value;
	}
	if(form.postal.value != "Postal Code/Zip")
	{
		postal = form.postal.value;
	}
	if(form.country.value != "Country")
	{
		country = form.country.value;
	}
	
	searchString = addr + ", " + city + ", " + state + " " + postal + ", " + country;
	
	geoCoder.getLocations(searchString,geoCodeCallback);
}

//The function gets the location from the servers and decides what to do
function geoCodeCallback(result)
{
	//Checks if the geocode was a success
	if(result.Status.code == G_GEO_SUCCESS)
	{
		//Checks for multiple results
		if(result.Placemark.length > 1)
		{
			//If so, display for user to select one
			$("didyoumean").innerHTML = "Did you mean:";
			for(var i = 0; i < result.Placemark.length; i++)
			{
				var m = result.Placemark[i].Point.coordinates;
				$("didyoumean").innerHTML += "<br />"+(i+1)+": <a href='javascript:geoCodeComplete("+m[1]+","+m[0]+")'>"+result.Placemark[i].address+"</a>";
			}
		}
		else
		{
			$("didyoumean").innerHTML = "";
			var m = result.Placemark[0].Point.coordinates;
			geoCodeComplete(m[1],m[0]);
		}
	}
	else
	{
		var reason = "Code " + result.Status.Code;
		if(reasons[result.Status.code])
		{
			reason = reasons[result.Status.code];
		}
		alert("Could not find '" + searchString + "' due to the following reason:<br />" + reason);
	}
}

//Finishes the geolocation translation by moving the marker
function geoCodeComplete(lat,lng)
{
	marker.setLatLng(new google.maps.LatLng(lat,lng));
	$('didyoumean').innerHTML = "";
	if(marker.isHidden())
	{
		marker.show();
	}
	getLatLng();
	if(urlZoom != null && urlZoom > 0)
	{
		map.setZoom(urlZoom);
	}
	else
	{
		map.setZoom(8);
	}
	map.setCenter(marker.getLatLng());
}

//Puts the marker on the given point upon right clicking on the map
function addMarker(point)
{
	marker.setLatLng(map.fromContainerPixelToLatLng(point));
	if(marker.isHidden())
	{
		marker.show();
	}
	getLatLng();
}

//Shows the marker and it's lat/lng
function pokeMarker(zoom)
{
	if(marker.isHidden())
	{
		marker.show();
		getLatLng();
		if(zoom != null && zoom > 0)
		{
			map.setZoom(zoom);
		}
		else
		{
			map.setZoom(8);
		}
		map.setCenter(marker.getLatLng());
	}
}

//Takes the marker bubble's form and gets directions
function getDirections(placemark)
{
	var opts = {};
	if($('walk').checked)
	{
		opts.travelMode = G_TRAVEL_MODE_WALKING;
	}
	if($('highways').checked)
	{
		opts.avoidHighways = true;
	}
	if($('type').value == 'to')
	{
		var callChain = new Chain;
		callChain.chain(dir.load("from: " + $('dirAddr').value + " to: " + placemark.address,opts),showBox('dirBox','mapDiv'));
	}
	else
	{
		if($('type').value == 'from')
		{
			var callChain = new Chain;
			callChain.chain(dir.load("from: " + placemark.address + " to: " + $('dirAddr').value,opts),showBox('dirBox','mapDiv'));
		}
		else
		{
			alert("Error getting directions.");
		}
	}
}

//Function that puts the marker at the latitude and longitude
function loadLat()
{
	marker.setLatLng(new google.maps.LatLng($('latitude').value,$('longitude').value));
	getLatLng();
	if(marker.isHidden())
	{
		marker.show();	
	}
	map.setZoom(8);
	map.setCenter(marker.getLatLng());
}

//Gets the zoom level of the map (for outside .js files)
function getCurrentZoom()
{
	return map.getZoom();
}
