//GLOBAL VARIABLES===========================================================================================================
//Variables that should come from XML========================================================================================
//default center of map (used when zoomed out to see entire area) We do have a better option which is to center the map when
//zoomed out to be the middle between the extreams of lat and lng in all our markers. This will likely one day need to happen
var cityCenterX;
var cityCenterY;
var markerSizeX;//width of marker icon
var markerSizeY;//height of marker icon
var defaultLegendDesc;
var GmapOptions = {mapTypes: [G_PHYSICAL_MAP,G_NORMAL_MAP,G_HYBRID_MAP]}; //im not really sure if we can get this from the
//xml file, if not then we'll just have to get it from sitecore or the ASCX file or something
//Variables that should stay here============================================================================================
var imageRoot = "";
var originalTitle;
var map; //our map
var gdir; //our google directions object
var categoriesArry = new Array(); //will hold a distinct list of marker categories
var currentMarker; //keeps track of the currently selected marker
var preLoadedImages = new Array(); //array that holds images (preloaded to prevent baloon display before download finishes)
var ddSelection; //select node "drop down list" in DOM that holds our markers
var gmarkers = new Array(); //list of all our markers
var toOrFrom = "to"; //keeps track of if we are going to or from our POI in directions
// === Array for decoding the failure codes ===
var reasons=[];
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.";
reasons[G_GEO_BAD_REQUEST]        = "A directions request could not be successfully parsed.";
reasons[G_GEO_MISSING_QUERY]      = "No query was specified in the input.";
reasons[G_GEO_UNKNOWN_DIRECTIONS] = "The GDirections object could not compute directions between the points.";
//lengthy styles broken out for easy modifcation and code readability
//style of div which is the "header/title" of the balloon
var balloonTitleStyle = 'class="content_module_header";' + 'border-bottom:none;width:400px;padding:3px;font-weight:bold;"';
var balloonInfoStyle = 'style="line-height:18px;margin-bottom:5px;border: 1px solid #ffffff;' +
	'border-top:none; width:400px;padding:3px;' + 'overflow:auto;" class="BG-color-bg-events02"' //style of balloons info div
var imageStyle = 'style="float:left;width:180px;margin-right:1em;"'; //style of point of interest image in balloon
var directionalInputStyle = 'style="border-top:1px solid #999;clear:both;"';
//HTML For the directional options div if the "to" or "from" options are selected.
var toHTML = '<center>Directions: <b>To here - <a href="javascript:gohere(\'from\')">From here</a></b></center>' +
	'<div style="margin-top:5px;">Enter Start Address, City and State: </div><div style="margin-top:5px;">' +
	'<input type="text" size=40 MAXLENGTH=60 name="userAddy" id="userAddy" value="" />' +
	'<INPUT value="Get Directions" TYPE="BUTTON" onclick="javascript:getDirections(\'to\');"></div>';
var fromHTML = '<center>Directions: <b><a id=_to href="javascript:gohere(\'to\')">To here</a> - ' + 
	'From here</b></center><div style="margin-top:5px;">Enter End Address, City and State: </div>' +
	'<div style="margin-top:5px;"><input type="text" SIZE=40 MAXLENGTH=60 name="userAddy" id="userAddy" value="" />' +
	'<INPUT value="Get Directions" TYPE="BUTTON" onclick="javascript:getDirections(\'from\');"></div>';

function loadGMap(){	//kickoff function that run once during page load
	if(!GBrowserIsCompatible()){	//if the browser doesn't work with google maps display an error
		alert("Sorry, the Google Maps API is not compatible with this browser");
	} else {	//otherwise continue with making the map
		//first we'll do a little initializing
		originalTitle = document.title;
		categoriesArry["all"] = "all"; //prime categories with "all" don't if you want only one category displaied at once

		// create the map
		map = new GMap2(document.getElementById("map"),GmapOptions);
		//add our controls to the map
		map.addControl(new GMapTypeControl());
		map.addControl(new GLargeMapControl());	//navigation/zoom control top left
		map.addControl(new DropDownMenuControl());
		//configure map behaviour
		map.enableScrollWheelZoom();
		//center and zoom map to city defautlts then save this position
		
		
		//create a GDirections Object used to manage directional routs and overlays
		gdir = new GDirections(map, document.getElementById("directions"));
		//add listenter to catch and handle directional errors
		GEvent.addListener(gdir, "error", function(){
			var code = gdir.getStatus().code;
			var reason="Code "+code;
			//if we have a friendly message for this error code use it, otherwise just use the error code
			if (reasons[code]) { reason = reasons[code]; } 
			alert("Failed to obtain directions, "+reason);
		});
		//Normally you'd think this method should fire on the open event of the direction object, but the markers
		//don't actualy get put on the map until the overlay event, so we can't remove (hide) them until then
		GEvent.addListener(gdir, "addoverlay", function() {
			if(toOrFrom == "to") {
				gdir.getMarker(1).hide();
			} else {
				gdir.getMarker(0).hide();
			}
		});
		// Read the marker data from XML
		readXML(markerXML);
		//when xml read is done it will automatically build the legend and fill the dropdown control with all markers
		//done

	}
	
}


//DEFINITONS=================================================================================================================
// ==========================================================================================================================
// ==========================================================================================================================

//=====Definition of custom control - DropDownMenuControl for area map markers ==============================================
function DropDownMenuControl() {}
DropDownMenuControl.prototype = new GControl();
DropDownMenuControl.prototype.initialize = function(map) {
	//create div to hold select control
	var container = document.createElement("div");
	container.id="divContainer";
	//create select control
	var selDropDown = document.createElement("select"); 
	selDropDown.id="MarkerSelection";
	//add a little padding above so we don't bump up against the maptype control
	selDropDown.style.marginTop = "5px";
	//add select control to container div
	container.appendChild(selDropDown);
	//create a default option
	var selOption = document.createElement("option"); 
	selOption.innerHTML =  "Select...";
	selOption.value =  "";
	//add defautl option to select control
	selDropDown.appendChild(selOption);
	//assign dropdown to global var so it can be manipulated by the other code
	ddSelection = selDropDown;
	//create listener so that choosing an option selects the corresponding marker
	GEvent.addDomListener(selDropDown, "change", function (){
		if(selDropDown.selectedIndex>0){ //only if they didn't choose the default "select..." option
			//trigger the click event of the corresponding marker just like it had been clicked on
			GEvent.trigger(gmarkers[selDropDown.options[selDropDown.selectedIndex].text], "click");
		}
	});
	//add the container to the map
	map.getContainer().appendChild(container);
	return container;
}
//make defautl potion upper right
DropDownMenuControl.prototype.getDefaultPosition = function (){
	return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(0, 25));
}
// ==========================================================================================================================

//FUNCTIONS==================================================================================================================
// ==========================================================================================================================
// ==========================================================================================================================

// ===== function which reads and parses XML holding the map's markers=======================================================
function readXML(path){
	//download the xml file from the path supplied by the caller
	var request = GXmlHttp.create();
	request.open("GET", path, true);
	//define function which runs when download is finished
	request.onreadystatechange = function() {
		if (request.readyState == 4){ //if we're down downloading the file
			//parse the XML into a DOM style object
			var xmlDoc = GXml.parse(request.responseText);
			//load all of the nodes with the tag of "marker" into an array of nodes
			//var markers = xmlDoc.documentElement.getElementsByTagName("marker");
			var settings = xmlDoc.getElementsByTagName("settings");
			cityCenterY = parseFloat(settings[0].getAttribute("cityCenterY"));
			cityCenterX = parseFloat(settings[0].getAttribute("cityCenterX"));
			markerSizeX = parseInt(settings[0].getAttribute("markerSizeX"));
			markerSizeY = parseInt(settings[0].getAttribute("markerSizeY"));
			defaultLegendDesc = settings[0].getAttribute("defaultLegendDesc");
			resetLegendDesc(defaultLegendDesc);
			//map.setCenter(new GLatLng(cityCenterX, cityCenterY), cityZoomLevel);
			map.setCenter(new GLatLng(41.228, -111.96054329), cityZoomLevel);
			map.savePosition();
			var markers = xmlDoc.getElementsByTagName("marker");
			for (var i = 0; i < markers.length; i++){ //for each marker node
				if(markers[i].nodeType==1){ //only if this node is an element
					//pull out all the useful attributes
					var category = markers[i].getAttribute("category");
					var lat = parseFloat(markers[i].getAttribute("lat"));
					var lng = parseFloat(markers[i].getAttribute("lng"));
					var html = markers[i].getAttribute("title");
					var info = markers[i].getAttribute("info");
					var addr = markers[i].getAttribute("addr");
                    var phone = markers[i].getAttribute("phone");
					var label = markers[i].getAttribute("title");
					var city = markers[i].getAttribute("city");
					var state = markers[i].getAttribute("state");
					var zip = markers[i].getAttribute("zip");
					//The marker may have 0 or more images which are contained in the child image elements of the marker
					//element. We will load then all into an array.
					var imageSrcArry = new Array();
					if(markers[i].childNodes.length > 0){ //if the marker element node has any children
						for(var x = 0; x< markers[i].childNodes.length;x++){ //for each child of the marker element node
							if(markers[i].childNodes[x].nodeType == 1){ //if this child is an element
								if(markers[i].childNodes[x].nodeName == "image"){ //if this child is an image element
									//push the image's src attribute inout our array
									imageSrcArry.push(imageRoot + markers[i].childNodes[x].getAttribute("src"));
								}
							}
						}
					}
					if(imageSrcArry.length == 0){ //if we didn't end up with any images for this marker push the noImage
						//image as a placeholder
						imageSrcArry.push(noImage);
					}
					// create the marker
					var point = new GLatLng(lat,lng);
					//currently although multiple images can belong to a marker we only display one (the last one in the
					//array). When we have time we will add the ability for all the images to rotate either at a timed 
					//interval or in response to clicks. This should be possible to acomplish using javascript alone and not
					//resorting to flash etc
					var marker = createMarker(point,label,html, phone, addr, city, state, zip, info, 
						imageSrcArry[imageSrcArry.length -1], category);
					//add the marker to our map
					map.addOverlay(marker);
				}
			}
			//now that the markers and categories are inplace we can build our legend
			buildLegend();
			//and fill the dropdown controll with all markers
			limitDropDown("all");
			resetMap();
			//select default marker
			if(defaultMarker.length > 0){
				GEvent.trigger(gmarkers[defaultMarker], "click");
			}
		}
	}
	//this must be done as cleanup for our GXmlHttp.response otherwise execution hangs
	request.send(null);
}
// ==========================================================================================================================

// ===== function which builds marker object ================================================================================ 
function createMarker(point, name, html, phone, addr, city, state, zip, info, imagesrc, category){
	//build an icon to use for the marker
	var baseIcon = new GIcon();
	baseIcon.image = markerIconRoot + category.replace(" ","_") + ".png";
	baseIcon.shadow = "";
	baseIcon.iconSize = new GSize(markerSizeX, markerSizeY);
	baseIcon.iconAnchor = new GPoint(markerSizeX / 2 , markerSizeY / 2);
	baseIcon.infoWindowAnchor = new GPoint(markerSizeX, 1);
	//create a new marker with the latlng passed in and the icon we just built
	var marker = new GMarker(point, baseIcon);
	//add some custom attributes to the marker that our code will use:
	marker.name = name;
	marker.fullAddress = addr + " " + city + " " + state + " " + zip;
	marker.category = category;
	//Build markers infowindow content
	var image = "<img src=\"" + imagesrc + "\" width=\"100%\">";
	// preload image to prevent falling out of balloon (which will happen if balloon is rendered before the image has finshed
	//downloading
	var img = new Image();
	img.src = imagesrc;
	preLoadedImages.push(img);
	//HTML to fill the balloon with
	var html = '<div id="balloon"><div ' + balloonTitleStyle + '><h4>' + html + '</h4></div><div ' + balloonInfoStyle + 
		'><div ' + imageStyle + '>' + image + '<div><font size="-1">' + addr + "<br/>" + city + " " + state + " " + zip + 
		'<br/>' + phone + '</font></div></div>' + info ;
	html += (showToFrom == true) ? '<div id="directionInput" ' + directionalInputStyle + 
		'><center>Directions: <b><a id=_to href="javascript:gohere(\'to\')">To here</a> - ' +
		'<a href="javascript:gohere(\'from\')">From here</a></b></center></div>' : '';
	html += '</div></div>';
	//add a listener so that the marker will react to being clicked
	GEvent.addListener(marker, "click", function() {
		//set the current marker to this marker
		currentMarker = marker;
		//clear any directions that may be displayed
		gdir.clear();
		//select the corresponding option in the dropdown (by name/Description)
		ddSelection.selectedIndex = getIndexOfSelectByOptionText(ddSelection,marker.name);
		//pan the map to this markers position
		map.panTo(this.getLatLng());
		//wait a specified numer of miliseconds to allow the pan to finish then zoom to the zoomed in level
		setTimeout("map.setZoom(markerZoomLevel);",zoomDelayMS);
		//assign the HTML into the marker as an attribute
		this.html = html;
		//wait a specified number of miliseconds to allow the pan to finish then open the info window for this marker
		//and fill it with it's own html content
		setTimeout("currentMarker.openInfoWindowHtml(currentMarker.html);",infoWindowDelayMS);
	});
	//Add listeners so that the page title shows the name of the marker when moused-over and resets when mouse-outed
	GEvent.addListener(marker, "mouseover",function (){
		document.title = marker.name;
	});
	GEvent.addListener(marker, "mouseout",function (){
		document.title = originalTitle;
	});
	//add this finsihed marker to the array of all markers
	gmarkers[name] = marker;
	//add this marker's category to the list of all categories (if it isn't alredy there) this will be used when building
	//the legend
	categoriesArry[category] = category;
	return marker;
}
// ==========================================================================================================================

// === function which finds the index of an option in a select control which has a matching text value=======================
function getIndexOfSelectByOptionText(select,text){
	for(var z =0;z<select.options.length;z++){ //for each opption in the select
		if(select.options[z].text == text){ //if this option matches the text supplied by caller return it's index
			return z;
		}
	}
	//if we fall out of the for loop without finding a match, return -1 to signify that no matching option found
	return -1;
}
// ==========================================================================================================================

// === function which shows (unhides) the requested markers and hides all others=============================================
function showMarkers(str_Category){
	for(var x in gmarkers){ // for each marker
		if(str_Category != "all" && gmarkers[x].category != str_Category){ //if this markers category doesn't mach the
			//supplied catetory and we aren't showing "all" then hide the marker (and close it's infowindow if open)
			gmarkers[x].hide();
			gmarkers[x].closeInfoWindow();
		} else {	//otherwise this marker matches the supplied category (or we're showing "all") so show it
			gmarkers[x].show();
		}
	}
	//now limit the contents of the dropdown control to show only markers that are visible
	limitDropDown(str_Category);
	//reset zoom to zoomed out level (city zoom)
	map.setZoom(cityZoomLevel);
}
// ==========================================================================================================================

// === function which limits the markers listed in the dropdown to only markers with the supplied catetory===================
function limitDropDown(category){
	//first we empty the dropdown, then we re-fill it with the appropriate options
	//we wrap this in a try so we don't error out if there aren't any children to remove
	try{
		var d = ddSelection.childNodes.length;
		for (var i = d; i > 1; i--){
			ddSelection.removeChild(ddSelection.lastChild);
		}
		for(var x in gmarkers){ //for each marker
			if(category != "all" && gmarkers[x].category != category){ //if this markers catetory doesn't match the category
				//we are "limiting" to AND we aren't limiting to "all" skip it
			} else {	//otherwise we want to include it
				//create and option
				var op = document.createElement("option");
				//fill it with this marker's info
				op.innerHTML =  gmarkers[x].name;
				op.value =  gmarkers[x].name;
				//add it as a child to the dropdown
				ddSelection.appendChild(op);
			}
		}
	}catch(e){
		//alert("Crap");
	}
}
// ==========================================================================================================================

// === function which builds legend based on categories =====================================================================
function buildLegend(){
	if(showLegend){
		for(var x in categoriesArry){	//for each category
			var imgLegendItem = document.createElement("img"); //make and image
			//the images src is the name of the category (with spaces replaced with _) and it lives
			//in the root defined by markerIconRoot. Marker icons are of type png
			imgLegendItem.src = markerIconRoot + categoriesArry[x].replace(" ","_") + ".png";
			imgLegendItem.name = categoriesArry[x]; //give the image a name and lable which is equal to the category name
			imgLegendItem.label = categoriesArry[x];
			//add and event listener so that when the legend icon is moused over it sets the legend text to a description
			//of that category
			GEvent.addDomListener(imgLegendItem,"mouseover", function() {
				document.getElementById("legendDesc").innerHTML = " Show " + this.label;
			});
			//add event listener sot hat when the legend icon is no loger moused over it sets the legend txt back to default
			GEvent.addDomListener(imgLegendItem,"mouseout", function() {
				resetLegendDesc(defaultLegendDesc);
			});
			//add style to the icon
			with(imgLegendItem.style){
				height = "25px";
				marginLeft = "7px";
			}
			//append the resulting image into the mapLegend div
			document.getElementById("mapLegend").appendChild(imgLegendItem);
			//add event listener so that when icon is clicked we show only that category's markers on the map
			GEvent.addDomListener(imgLegendItem, "click", function (){ showMarkers(this.name);}); 
		}
	}
}
// ==========================================================================================================================

// === function which sets the legend text back to the default===============================================================
function resetLegendDesc(defaultDesc){
	if(showLegend){
		document.getElementById("legendDesc").innerHTML = defaultDesc;
	}
}
// ==========================================================================================================================

// === function which builds directions rout and overlap on the map==========================================================
function getDirections(direction) {
	//When this function is called we "load" directions using the directions object between the point of interest's
	//address and the address the user has supplied. If they want directions "to" the POI then we do directions from
	//their address to the POI. If they want directions "from" the POI then we do directions from POI to their address
	if(direction == "to") {
		var fromAddress = document.getElementById("userAddy").value;
		var toAddress = currentMarker.fullAddress;
		toOrFrom = "to";
	} else if(direction == "from") {
		var fromAddress = currentMarker.fullAddress;
		var toAddress = document.getElementById("userAddy").value;
		toOrFrom = "from";
	}
	//hide the balloon when in directions mode
	var w = map.getInfoWindow();
	w.hide();
	//load directions object.
	var dirReq = "from: " + fromAddress +" to: " + toAddress;
	gdir.load(dirReq);
}
// ==========================================================================================================================

// === function which shows the 'to here' or 'for here' form inside the bubble===============================================
function gohere(tofrom) {
	//This function sets the directional input element to contain the "to" or "from" form
	if(tofrom == "to") { 
		document.getElementById("directionInput").innerHTML = toHTML;
	} else if (tofrom == "from") {
		document.getElementById("directionInput").innerHTML = fromHTML;
	}
	//by re-opening the infowindow with the same content that it already has the balloon is re-sized to fit the
	//new "bigger" content (otherwise the content falls out of the bottom of the balloon
	currentMarker.openInfoWindow(document.getElementById("balloon"));
	//Here I try to set focus to the text input control, but I can't get it to work :(
	document.all('userAddy').focus();
}
// ==========================================================================================================================

// === function which sets map back to original conditions ==================================================================
function resetMap(){
	//things that should happen to reset the map:
	//Directions should be cleared
	gdir.clear();
	//"all" categories should be selected
	showMarkers("all");
	//map should be zoomed out
	map.setZoom(cityZoomLevel);
	//all balloons should be popped
	for(var x in gmarkers){
		gmarkers[x].closeInfoWindow();
	}
	//map type should be reset
	map.setMapType(GmapOptions.mapTypes[0]);
	//map should pan back to city center
	//commented out by bk 11/13/2009
	map.panTo(new GLatLng(cityCenterX, cityCenterY));
}
// ==========================================================================================================================
