/**

	
	Version: 0.5.1
	
	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.
	
*/

      // this variable will collect the html which will eventualkly be placed in the side_bar
      var side_bar_html = "";
    
      // arrays to hold copies of the markers and html used by the side_bar
      // because the function closure trick doesnt work there
      var gmarkers = [];
      var htmls = [];
      var i = 0;

function drawMap(url) {
	
	// Specify a default url if one is not provided
	if (!url) {
		url = "countymapJCsummits.xml";
	} 
	/*
	else {
		var url = "county.xml";
	}

	*/
	// 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++) {
			
				// Get the single borderSet pointed at by the index (i)
				var borderSetNode = borderSetInfo.item(i);
				
				// 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);
				borderArray = null;
				map.addOverlay(borderPolyline);
					
			}

	    	GEvent.addListener(map, 'click', function(overlay, point) {
		    // point = Lat/Lon:(4.7021484375, 51.971345808851716)
		    var matchll = /\(([-.\d]*), ([-.\d]*)/.exec( point );
	            	var lat = parseFloat( matchll[1] );
	            	var lon = parseFloat( matchll[2] );
			lat = lat.toFixed(6);
			lon = lon.toFixed(6);
	            	document.getElementById("frmLat").value = lat;
	      	    	document.getElementById("frmLon").value = lon;
		     });

	
			// 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');
				if (pointLinkInfo) {	

					var pointLinkNode = pointLinkInfo.item(0);
					if (pointLinkNode) {
						var pointLink = getInnerText(pointLinkNode);
						var pointTarget = pointLinkNode.getAttribute('target');

					}


				}

			
				// 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) {
					if (!pointTarget) {
						html = html + '<b><a href=\"' + pointLink + '\">' + pointTitle + '</a></b>';

					}
					else
					{
						html = html + '<b><a href=\"' + pointLink + '\" target=\"' + pointTarget + '\">' + 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,pointTitle, html)
				map.addOverlay(marker);	
				// sidebar					
				document.getElementById("side_bar").innerHTML = side_bar_html;
			}
		}
    }
    
    req.send(null);
 
}

/**
	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, name, 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);
  });

        // save the info we need to use later for the side_bar
        gmarkers[i] = marker;
        htmls[i] = html;
        // add a line to the side_bar html
        side_bar_html += '<a href="javascript:myclick(' + i + ')">' + name + '</a><br>';
        i++;



  return marker;
}

      // This function picks up the click and opens the corresponding info window
function myclick(i) {
        gmarkers[i].openInfoWindowHtml(htmls[i]);
}




/**
	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);
}

/*
//function getCounties(){

	/* Create the request. The first argument to the open function is the method (POST/GET),
		and the second argument is the url... 
		document contains references to all items on the page
		We can reference document.form_category_select.select_category_select and we will
		be referencing the dropdown list. The selectedIndex property will give us the 
		index of the selected item. 
	*/
	//var docname='countylist.php?stateid=' + document.getElementById('stateId').value;
	//http.open('get',docname);
	//http.open('get', 'countylist.php?stateid=' + document.getElementById('stateId').selectedIndex);

	/* Define a function to call once a response has been received. This will be our
		handleProductCategories function that we define below. */
	//http.onreadystatechange = handleCounties; 
	/* Send the data. We use something other than null when we are sending using the POST
		method. */
	//http.send(null);
//}
	
	/* Function called to handle the list that was returned from the internal_request.php file.. */
//	function handleCounties(){
		/* Make sure that the transaction has finished. The XMLHttpRequest object 
			has a property called readyState with several states:
			0: Uninitialized
			1: Loading
			2: Loaded
			3: Interactive
			4: Finished */
//		if(http.readyState == 4){ //Finished loading the response
			/* We have got the response from the server-side script,
				let's see just what it was. using the responseText property of 
				the XMLHttpRequest object. */
//			var response = http.responseText;
			/* And now we want to change the product_categories <div> content.
				we do this using an ability to get/change the content of a page element 
				that we can find: innerHTML. */
				//alert(response);
//			document.getElementById('county').innerHTML = response;
//		}
//	}

/*
	Version History
	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
*/

