/**

	
	Version: 0.5.2
	
	Usage
	
	The user of this script must register with Google in order to create a map developer's "key"
	that will allow them to create maps. This is done at http://www.google.com/apis/maps/signup.html.
	
	In the <head> of the document that will generate the map, the user must follow Google's directions
	to specify the script (and key).
	
	Next, the user must add this script as follows:
	
		<script src="map.js"></script>
		
	The closing </script> tag is mandatory, <script /> is not accepted by browsers. Also, if the script
	is moved to a directory different from the calling document, the src must reflect the actual
	location (relative or absolute) of the script.
	
	Once the script has been specified in the <head> of the document, it must be called by the <body> of the
	document. The simples way is to have it executed when the document is loaded:
	
		<body onload='javascript:drawMap()'>
		
	Within the <body> itself, the must be a section created for the map. Determine where on the page
	the map will be placed, and insert these lines:
	
		<div id="map">
		
		</div>
		
	We're still not done yet! Internet Explorer, being a little "different", needs certain things
	spelled out for it.
	
	At or near the top of your document, replace your <html> tag with this:
	
		<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
		
	What this means is rather technical, but it will not affect the rest of the content of your 
	page.
	
	Now, go back to your <head> section and insert this:
	
	  	<style>
    		#map	{width: 640px; height: 480px}
    		v\:* {behavior:url(#default#VML);}
    	<style>
    	
    The #map section specified the width and height of the map to be created. The v\: section is a 
    Microsoft "feature" called VML, which needs to be specified in order for maps with any borders
    to be displayed in IE.
    
    That should about do it! Remember to upload three files to your site:
    
    (your page).html
    county.xml
    map.js (this file)
    
    Licensing
    
    This program is licensed under the GNU Public License, which can be referenced at
    http://www.gnu.org. While this allows you to change and do whatever you want with this code, I
    would appreciate SOME recognition for the work I've done on it.
*/

/**
	This function does the dirty work of creating a customized Google Map of a county specified
	in the county.xml file. The user should not have to customize this function, although it
	does limit the user's abilities in some respects by limiting their options. However, it
	is aimed at non-programmers who are willing to accept that tradeoff.
	
*/
function drawMap(url) {
	
	// Specify a default url if one is not provided
	if (!url) {
		url = "countymap.xml";
	} 
	
	// Check if the Browser is compatible with Google Maps
	if (GBrowserIsCompatible()) {
		// Create an HTTP request and get the county.xml file
		var req = GXmlHttp.create();
		req.open("GET",url,true);
		
		// When the file is received, process it.
		req.onreadystatechange = function() {
	        if (req.readyState == 4) { 
		        
		        // Get the actual XML Document
		        var doc = req.responseXML;
		        
		        // Get "all" of the county elements (though we only care about the first one!)
		        var countyInfo = doc.getElementsByTagName('county');
					        
				// Get the <county> element
				var countyNode = countyInfo.item(0);
				
				// Get the attributes of the <county> element (name, Lng, Lat, defaultZoom)
				var countyName = countyNode.getAttribute('name');
				var countyCtrLng = parseFloat(countyNode.getAttribute("ctrLng"));
				var countyCtrLat = parseFloat(countyNode.getAttribute("ctrLat"));
				var ctrPoint = new GPoint(countyCtrLng, countyCtrLat);
				var zoomLevel = parseInt(countyNode.getAttribute("zoom"));
				
				// Draw the initial map
				var map = new GMap(document.getElementById("map"));
				map.addControl(new GLargeMapControl()); 
				map.addControl(new GMapTypeControl());
				map.centerAndZoom(ctrPoint,zoomLevel);
				
				// Put in the defined borders
				
				// Get all of the bordersets (normally there will just be one, but it's not limited)
				var borderSetInfo = doc.getElementsByTagName('borderSet');
				for (var i = 0; i<borderSetInfo.length; i++) {
				
					// Need to get the color attribute for the borderSet or it will default to blue
					//var borderColor = borderSetInfo.getAttribute("color");
					// Get the single borderSet pointed at by the index (i)
					var borderSetNode = borderSetInfo.item(i);
					var borderColor = borderSetNode.getAttribute('color');
					
					// Get all of the <border> tags for that borderSet
					var singleBorderInfo = borderSetNode.getElementsByTagName('border');
					
					// Create an array to hold the border GPoints
					var borderArray = new Array();
					
					// Loop through all of the <border> tags
					for (var j = 0; j<singleBorderInfo.length; j++) {
						
						// Get a single <border>
						var singleBorderNode = singleBorderInfo.item(j);
						
						// Get the lng and lat from that <border>
						var borderlng = parseFloat(singleBorderNode.getAttribute("lng"));
						var borderlat = parseFloat(singleBorderNode.getAttribute("lat"));
							
						// Push a new GPoint onto the array with those coordinates
						borderArray.push(new GPoint(borderlng, borderlat));
							
					}
					
					// Create the Polyline overlay, free the array memory (probably unessesary), and add
					// the overlay
					borderPolyline = new GPolyline(borderArray, borderColor);
					borderArray = null;
					map.addOverlay(borderPolyline);
						
				}
		
				// Put in the Markers
				var pointInfo = doc.getElementsByTagName('point');
				for (var i=0; i<pointInfo.length; i++) {
					var pointNode = pointInfo.item(i);
					var pointLng = parseFloat(pointNode.getAttribute("lng"));
					var pointLat = parseFloat(pointNode.getAttribute("lat"));
					var markerPoint = new GPoint(pointLng, pointLat);
					
					var pointTitleInfo = pointNode.getElementsByTagName('pointTitle');
					var pointTitleNode = pointTitleInfo.item(0);
					var pointTitle = getInnerText(pointTitleNode);
					
					var pointDescInfo = pointNode.getElementsByTagName('pointDesc');
					var pointDescNode = pointDescInfo.item(0);
					var pointDesc = getInnerText(pointDescNode);
					pointDesc = pointDesc.replace('\n','<br />');
					
					// Get <pointLink> element and contents
					var pointLinkInfo = pointNode.getElementsByTagName('pointLink');
					var pointLinkNode = pointLinkInfo.item(0);
					var pointLink = getInnerText(pointLinkNode);
					
					// Get <pointIcon> element and SRC attribute
					var pointIconInfo = pointNode.getElementsByTagName('pointIcon');
					if (pointIconInfo) {
						var pointIconNode = pointIconInfo.item(0);
						if (pointIconNode) {
							var pointIconSrc = pointIconNode.getAttribute('src');
							var pointIconAlt = pointIconNode.getAttribute('shadow');
							// TODO: create the GIcon
						}
					}
					
					// Get <pointImage> element and SRC attribute
					var pointImageInfo = pointNode.getElementsByTagName('pointImage');
					var pointImageNode = pointImageInfo.item(0);
					var pointImageSrc = pointImageNode.getAttribute('src');		
					
					// Create the contents of the InfoWindow
					var html = '';
					
					// If an image is specified for the infoWindow, add it to the HTML string
					if (pointImageSrc.length > 0) {
						
						html = html + '<img src=\"' + pointImageSrc + '\" align=\"left\" />';
					}
					
					// If a Link is specified, link the title of the Infowindow to it
					if (pointLink.length > 0) {
						html = html + '<b><a href=\"' + pointLink + '\">' + pointTitle + '</a></b>';
					} else {
						html= html + "<b>" + pointTitle + "</b><br />";
					}
					// Add the description
					html = html + "<p>"	+ pointDesc + "</p>";
					// TODO: create the Icon to be used for the marker.
					
					// Cache the marker icons
					cacheImage('http://www.google.com/mapfiles/marker.png');
					cacheImage('http://www.google.com/mapfiles/shadow50.png');
					// Create the marker and add it to the map
					var marker = createMarker(markerPoint, html)
					map.addOverlay(marker);						
					
				}
			}
	    }
	    
	    req.send(null);
	} else {
		
		var paraNode = document.createElement('p');
		document.getElementById('map').appendChild(paraNode);
		paraNode.text = 'We apologize, but the Mapmaker is apparently not compatible with your web browser.';
		// Fill the DIV with an error message instead of the map
		
	}
    
 
}

/**
	This function creates a GMarker to be placed on a map.
	
	@param	point	a GPoint specifying where the item is to be placed on the map
	@param	html	a String containing the HTML to be put into the InfoWindow
	@return			a GMarker that can be placed on the map
*/
function createMarker(point, html) {
  var marker = new GMarker(point);

  // Show this marker's index in the info window when it is clicked
  GEvent.addListener(marker, "click", function() {
    marker.openInfoWindowHtml(html);
  });

  return marker;
}

/**
	This function gets the text inside a specified tag, since the function to do
	so tends to be browser specific.
	
	@param	node	a DOM Node containing the tag with contents to be read
	@return			a String with the contents of the tag
	
*/
function getInnerText (node) {
   var innerText = '';
   if (node.nodeType == 3) {
     return node.nodeValue;
   }
   else {
     for (var i = 0; i < node.childNodes.length; i++) {
       innerText += getInnerText(node.childNodes[i]);
     }
     return innerText;
   }

} 

/**
	This image attempts to speed up the display process by pre-caching images. In this
	case, the marker icons will be cached in advance to try to speed up the process of 
	adding markers to the map.
	
	This will probably only result in a one-time speedup, but anything helps.
	
	@param	url	a URL of an image
*/
function cacheImage(url) {
	
	var image = new Image();
	image.src = url;
		
}

/**
	This function converts a point from radians to decimal
	
	@param 	s	an Integer representing degrees
	@param	m	an Integer representing minutes
	@param	s	an Integer representing seconds
	@return		a Float representing the decimal degrees
*/
function deg2dec(d, m, s) {

	return d + (m/60) + (s/3600);	
}

/**
	This function takes an array of values and returns an array
	with the duplicate values removed.
	
	@param	arr	an Array to be searched for duplicate values
	@return		an Array with duplicate values removed
*/
function array_unique(arr) {
	var newArray = [];
	var existingItems = {};
	var prefix = String(Math.random() * 9e9);
	for (var ii = 0; ii < arr.length; ++ii) {
		if (!existingItems[prefix + arr[ii]]) {
			newArray.push(arr[ii]);
			existingItems[prefix + arr[ii]] = true;
		}
	}
	return newArray;

} 

/**
	This function rounds a floating point number to a specified precision. The
	function should be used when wanting to reduce the detail of latitude and
	longitude coordinates. Once detail is reduced, array_unique can removed duplicate
	coordinate entries before they are used to create overlays.
	
	@param	num		a Float number to be rounded
	@param	prec	an Integer representing the desired decimal precision
	@return			a rounded Float
*/
function roundFloat(num, prec) {
	
	myNumber = new Number(num);
	return myNumber.toFixed(prec);
	
}

	// Temporary JS location, move to external later
	function createRequestObject(){
		var request_o; //declare the variable to hold the object.
		var browser = navigator.appName; //find the browser name
		if(browser == "Microsoft Internet Explorer"){
			/* Create the object using MSIE's method */
			request_o = new ActiveXObject("Microsoft.XMLHTTP");
		}else{
			/* Create the object using other browser's method */
			request_o = new XMLHttpRequest();
		}
		return request_o; //return the object
	}
	
	var http = createRequestObject(); 

/**	
	This function generates an AJAX request to create a <select> filled with the state names.
*/
function getStates() {
	var docname='ajax.php?action=1';
	http.open('get',docname);
	http.onreadystatechange = function() {
		if (http.readyState == 4) {
			var response = http.responseText;
			//selNode = document.createTextNode(response);
			selNode = document.createElement('SELECT');
			//document.getElementById('stateSelect').innerHTML = response;	\
			document.getElementById('stateSelect').appendChild(selNode);
		}	
	};
	http.send(null);

}


function getCounties() {
	if (document.getElementById('selState') == null) {
		alert('No selState node!');
	}
	var docname='ajax.php?action=1+param=' + document.getElementById('selState').value;
	http.onreadystatechange = function() {
		if (http.readyState == 4) {
			var response = http.responseText;
			document.getElementById('countySelect').innerHTML = response;	
		}
	};
}

function makeSelectElement(elementName, optionArray, attributeArray) {
	//element=document.createElement("<select name='selState'>");
	//element = document.createElement('select');

	element = document.createElement('select');
	element.name = "test";
	//var o = document.createElement('option');
	//o.value="";
	//o.text="Blah";
	//element.appendChild(o);

	//element.setAttribute("name",elementName);
	//element.options = optionArray;
	

	for (var i=0; i<attributeArray.length; i++) {
		var firstQuote=attributeArray[i].indexOf('\"');
		var eqPlace=attributeArray[i].indexOf('\"');
		var lastQuote=attributeArray[i].lastIndexOf('\"');
		
		var attribute=attributeArray[i].substr(0,eqPlace-1);
		var attrValue=attributeArray[i].substr(firstQuote+1, lastQuote-1);
		
		if (attribute == 'onChange') {
			element.onChange=attrValue;
		}
		
	} 
	alert(element);
	return element;
		
}

function makeOptionElement(elementName, optionValue, optionText) {
	return new Option(optionText, optionValue);
}


/*
	Version History
	0.5.2 - Fixed border color display, added AJAX functions, version bump to match generator version
	0.5.1 - Changed drawMap() to deal with updated XML design
	0.5.0 - Removed usgs2dec() function, added cacheImage(), array_unique(), roundFloat() functions
			moved createRequestObject(), getCounties(), and handleCounties() to this file
	0.4.1 - Bugfix release (line breaks in info bubbles, disable usgs2dec function)
	0.4.0 - First working version of reusable code, with XML loading via AJAX
*/

