//sao map (TM) Data Processing Script  --
//Copyright 2007 CartoSoft, LLC
//You may use any of the code in this script as long as the above copyright and URL notice is left in place

 //<![CDATA[

if (GBrowserIsCompatible())
{
	var map = null;
	var iconImage = null;
	var geoSwitch;
	var bounds = new GLatLngBounds();
	var loader;
	var clickId;
	var lastClick = -1;
	var existingMarkers = [];
	var baseicon;
	var boundPoly;
	var saoiOverlay;
	var saoTipWrapper;
	var saomapLat;
	var saomapLng;
	var idnumber = 0;
	//Declare array objects
	var sidePoints = [];
	var gmarkers = [];
	var htmls = [];
	var nodes = [];
	var nodehtmls = [];
	var dirTo = [];
	var dirFrom = [];
	var dirNearby = [];	
	//Set a hash table and sort out the multiple listings
	var keycounts = [];
	
	//Highlight the table row in the sidepanel...activated from the click inside the marker info window
	function highlight(a) {
		if (lastClick != -1) {
		if (document.getElementById(lastClick)) {
			document.getElementById(lastClick).style.background = "none";
		}
		}
	document.getElementById(a).style.background = "#C6DAFF";
	document.getElementById(a).scrollIntoView(false);
	lastClick = a;
	}
	
	//Define the hash function
	function hash(lng, lat)	{
	return(lng + ":" + lat);
	}

	//Add overlays to map (called by loader)
	function addPoints (marker) {
	map.addOverlay(marker);
	}
	
	// This function picks up the click and opens the corresponding info window
	function findMarker(mn) {
	gmarkers[mn].openInfoWindowHtml(htmls[mn]);
	sideLabelOut();
	}
	
	//This function shows/hides the directions divs
	function showDir(idir, dirStr) {
		if (dirStr == "to") {
			gmarkers[idir].openInfoWindowHtml('<div class="infowindow">'+dirTo[idir]+'</div>');
		}
		else {
			gmarkers[idir].openInfoWindowHtml('<div class="infowindow">'+dirFrom[idir]+'</div>');
		}
	}
	
	//This function shows/hides the nearby div
	function nearby(idir) {
		gmarkers[idir].openInfoWindowHtml('<div class="infowindow">'+dirNearby[idir]+'</div>');
	}
	
	//This function zooms the map to a select marker
	function saozoomto(saoPoint, saoz) {
		map.setCenter(gmarkers[saoPoint].point);
		var gmapZoom =parseInt(map.getZoom()/3);
		if (saoz == "in") {
			map.setZoom(map.getZoom()+gmapZoom);
		}
		else {
			map.setZoom(map.getZoom()-gmapZoom);
		}
	}

	//This function zooms the map to STREET level select marker
	function saozoomStreet(saoPoint) {
		map.setCenter(gmarkers[saoPoint].point);
		map.setZoom(17);
	}
	
	function showsaoTiles() {
		//Get the image tiles to show the points
		var saoiLayer = new GTileLayer(new GCopyrightCollection(''), 3, 15);
		
		//Get the tile URL and get the tile
		saoiLayer.getTileUrl = function (tile, zoom) {
			var tPage = kmlFile.replace(/kml/i,"img");
			var tUrl = tPage+"?lng="+tile.x+"&lat="+tile.y+"&z="+zoom;
			return tUrl;
		};
		
		//A little checking
		saoiLayer.isPng = function() { return false; }
		saoiOverlay = new GTileLayerOverlay(saoiLayer);
		map.addOverlay(saoiOverlay);
	}
	
    // Tooltip function (from Mike Williams)
    function showsaoTip(saom) {
      	saoTipWrapper.innerHTML = 	'<div class="saobox">'+
									'<div class="saoboxcontent">'+saom.tip+'</div>'+
									'</div>';
	var saoPoint=map.getCurrentMapType().getProjection().fromLatLngToPixel(map.fromDivPixelToLatLng(new GPoint(0,0),true),map.getZoom());
	var saoOffset=map.getCurrentMapType().getProjection().fromLatLngToPixel(saom.getPoint(),map.getZoom());
	var saoAnchor=saom.getIcon().iconAnchor;
	var saoWidth=saom.getIcon().iconSize.width;
	var saoHeight=saoTipWrapper.clientHeight;
	var saoPos = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(saoOffset.x - saoPoint.x - (saoAnchor.x*1.5) + saoWidth, saoOffset.y - saoPoint.y - saoAnchor.y - (saoHeight/12))); 
	saoPos.apply(saoTipWrapper);
	saoTipWrapper.style.display="block";
    }

	//Show and hide map marker labels based on hovers in sidebar
	function sideLabelOver(i) {
		showsaoTip(gmarkers[i])
	}
	//Hide the label
	function sideLabelOut() {
		saoTipWrapper.style.display="none";
	}
	
	//Call this function from body onLoad event in html output
	function load(){

		map = new GMap2(document.getElementById("map"));
		
		//Set the initial center point (this will be adusted at the end to the bounds of the data points selected)
		var centerPoint = new GLatLng(10,0);
			map.addControl(new GLargeMapControl());
			map.addControl(new GMapTypeControl());
			map.addControl(new GScaleControl());
			map.addControl(new GOverviewMapControl());
			map.enableDoubleClickZoom();
			map.setCenter(centerPoint, 2);
			
			//Add the tool tip div
			saoTipWrapper = document.createElement("saobox");
			saoTipWrapper.style.display = "none";
			map.getPane(G_MAP_FLOAT_PANE).appendChild(saoTipWrapper);
			
		//Set the initial center point (this will be adusted at the end to the max bounds of the data points selected)
		var centerPoint = new GLatLng(44.933696,-120.52002);
			map.addControl(new GLargeMapControl());
			map.addControl(new GMapTypeControl());
			map.addControl(new GScaleControl());
			map.addControl(new GOverviewMapControl());
			map.enableDoubleClickZoom();
			map.setCenter(centerPoint, 6);
			
			saomapLat = 44.933696;
			saomapLng = -120.52002;
			
		//Set the icon
		baseIcon = new GIcon();
				
		//Add the map listeners
		GEvent.addListener(map,'moveend',function() {
			//Get the map center and compare lat/lng with existing saomapLat and saomapLng.  This prevents the loadData function from being called numerous times by moveend events triggered by the API
			var saomapCenter = map.getCenter();
			if (saomapLat != (saomapCenter.lat()) && saomapLng != (saomapCenter.lng())) {
			loadData(false);
			}
		});
		GEvent.addListener(map,'zoomend',function() {
			 loadData(true);
		});
		
		//Call loadData function to parse the URL
		loadData(true);
	
	} //end load function
	
	//loadData function...called when map state changes
	function loadData(showLoad) {
			
		//Instantiate the loader...
		//Load MLoader with document elements
		//First, flush the text from the last load
		//document.getElementById("loadingText").innerHTML = "";
		document.getElementById("tally").innerHTML = "";
		
		if (showLoad == true) {
		loader = new MLoader(map, document.getElementById("loading"), document.getElementById("loadingText"),
					document.getElementById("bar"), document.getElementById("fill"), document.getElementById("loadingButton"),
					document.getElementById("tally"));
					loader.show("Loading Data", true);
		}
		
		//Declare other objects
		var i = 0;
		var cnum = 0;
		var sidehtml="";
		
		//Get the map extent (bounds)
		var bounds = map.getBounds();
		var sw = (bounds.getSouthWest()).toUrlValue();
		var ne = (bounds.getNorthEast()).toUrlValue();
		var swArray = sw.split(",");
		var neArray = ne.split(",");
		//Set up the coords for URL (for Ajax call)
		var coordURL = "?minlng="+swArray[1]+"&minlat="+swArray[0]+"&maxlng="+neArray[1]+"&maxlat="+neArray[0];
		
		//Loop through any existing markers that will no longer be shown in the extent
		for (j in existingMarkers) {
			if (!bounds.contains(existingMarkers[j].getPoint())) {
				map.removeOverlay(existingMarkers[j]);
				delete existingMarkers[j];
				delete sidePoints[j];
				delete gmarkers[j];
				delete htmls[j];
				delete nodehtmls[j]
			}
		}
				
		//This function creates the map markers.  createMarker(point as GPoint, Title, mhtml as string, ihtml as String, Click ID)
		function createMarker(point, titleValue, mhtml, ihtml, cId, cUrl) {
			var key  = hash(point.lng(), point.lat());
			
			mhtml = '<div style="overflow:auto; height:200px;">'+mhtml+'</div>';
			ihtml = '<div style="overflow:auto; max-height:296px;">'+ihtml+'</div>';
					
			//Create the Google icon based on the iconType (company, competition, customer)
			var icon = new GIcon(baseIcon);

			if (keycounts[key] == 1)
				{
					//Single Listing.  The marker is created with the GPoint (first variable passed to function) and the icon created above.
					//This generates the tooltip and graphic representation of the marker (i.e., icon)
					var marker = new GMarker(point, {title:titleValue, icon:icon});
					marker.tip = titleValue;
					
					//Attach an event listener to the marker.  Show information in the info window.
					GEvent.addListener(marker, "click", function() {
					marker.openInfoWindowHtml('<div class="infowindow">'+ihtml+'</div>');
					highlight(cId);
					});	

					//Remove highlight of the table rows in the side panel when the info window is closed.
					GEvent.addListener(marker, "infowindowclose", function(){
						document.getElementById(cId).style.background="none";
					});
				}
				else
				{
					//Multiple Listings.  The marker is created with the GPoint (first variable passed to function) and the icon created above.
					//This generates the tooltip and graphic representation of the marker (i.e., icon)
					var imgclass = "Multiple Points";
					var marker = new GMarker(point, {title:imgclass, icon:icon});
					marker.tip = titleValue;
					
					
					//Attach an event listener to the marker.  Show information in the info window.
					GEvent.addListener(marker, "click", function() {
					marker.openInfoWindowHtml('<div class="infowindow"><b>This point has ' + keycounts[key] + ' listings.</b><br>'+mhtml+'</div>');
					});	
					
					//Remove highlight of the table rows in the side panel when the info window is closed.
					GEvent.addListener(marker, "infowindowclose", function(){
						if (lastClick != -1) {
						document.getElementById(cId).style.background="none";
						}
					});
				}

			//Only do this if the marker is net new
			if (!existingMarkers[idnumber] && !htmls[idnumber] && bounds.contains(point)) {
				//mhtml for the INFO PANEL (i.e,, the list on the left that contains the titles, etc.).
				sidePoints[idnumber] = point;
				gmarkers[idnumber] = marker;
				htmls[idnumber] = '<div class="infowindow">' + ihtml + '</div>';
			}
			sidehtml += '<tr id="'+cId+'" onMouseOver="sideLabelOver(\''+idnumber+'\');headerOver(\''+cId+'\')" onMouseOut="sideLabelOut();headerOut(\''+cId+'\')" class="siderow"><td valign="middle" width="35" align="center" style="border-bottom: 1px solid #999999"><div class="header" title="'+imgclass+'">'+cnum+'.</div></td>';
			sidehtml += '<td style="padding-bottom:10px; padding-top:10px; border-bottom: 1px solid #999999">';
			sidehtml += '<a href="'+cUrl+'" target="_number" class="header">'+titleValue+'</a></td>';
			sidehtml += '<td style="padding-bottom:10px; padding-top:10px; padding-right: 5px; border-bottom: 1px solid #999999"><a href="javascript:highlight(\''+cId+'\');findMarker(\''+idnumber+'\')" title="Map It" class="mapit"><img src="icons/mapit.gif" alt="Map It" title="Map It" align="absmiddle"/></a>';
			sidehtml += '</td></tr>';	
			i++;
			return marker;
		}
					
		//This function processes the sao map output (XML) and adds the markers to the map...
		GDownloadUrl(kmlFile+coordURL, function(data, responseCode) {
			
			nodes = [];
			nodehtmls = [];
		
			var xmlDoc = GXml.parse(data);
				
				//Check to see the number of records returned is more than 300...if so update the sidebar with  message
				var kmlcount = xmlDoc.documentElement.getElementsByTagName("Document")[0].getAttribute("count");
			
				if (parseFloat(kmlcount) > 300) {
					//Some cleanup
					map.clearOverlays();				
					existingMarkers = [];
					loader.hide(true); //hide the loader
					document.getElementById("resultpanel").innerHTML = '<h2>Please Note:</h2><h4>There are too many points to display at this zoom level (<span style="color:#FF0000">'+kmlcount+' points</span>).<br/><br/>The small red points <img src="icons/redpoint.png" alt="Red Point" title="Red Point" style="vertical-align:middle")/> on the map give an indication of the distribution of the data points.  Clickable map markers will be displayed on the map once you zoom in to an extent that contains 300 points or less.<br/><br/>Please zoom in to decrease the number of points being mapped.</h4>';
					
					//Show the image tiles that give a general idea of where the points are
					showsaoTiles();
					return false;
				}

				//If the number of records is 0, then update the sidebar with message
				if (parseFloat(kmlcount) == 0) {
					//Remove the Boundary Polygon
					//map.removeOverlay(boundPoly);
					loader.hide(true); //hide the loader
					document.getElementById("resultpanel").innerHTML = '<h2>Please Note:</h2><h4>There are <span style="color:#FF0000">no</span> points to display in the current extent.<br>Please zoom in, zoom out, or pan the map to an extent that includes points.</h4>';
					return false;
				}
				
				//Remove the Boundary Polygon
				map.removeOverlay(saoiOverlay);
				
				//Update baseIcon attributes (get from KML)
				var iconElement 			 = xmlDoc.documentElement.getElementsByTagName("Icon")[0];
				var iconref 				 = iconElement.getElementsByTagName("href")[0];
				baseIcon.image  			 = iconref.firstChild.nodeValue;
				var iconWidth 				 = 25;
				var iconHeight 				 = 25;
				baseIcon.iconSize            = new GSize(iconWidth,iconHeight);
				baseIcon.iconAnchor          = new GPoint((iconWidth/2), iconHeight);
				baseIcon.infoWindowAnchor    = new GPoint((iconWidth/2), (iconHeight/2));
				
				var coords = xmlDoc.documentElement.getElementsByTagName("coordinates");
					//Populate the hash table
					for (var i = 0; i < coords.length; i++) {
						var points = coords[i].firstChild.nodeValue;
						var pointsArray = points.split(",");
						var key = hash(parseFloat(pointsArray[0]), parseFloat(pointsArray[1]));
							keycounts[key] = 0;
					}
					for (var i = 0; i < coords.length; i++)	{
						var points = coords[i].firstChild.nodeValue;
						var pointsArray = points.split(",");
						var key = hash(parseFloat(pointsArray[0]), parseFloat(pointsArray[1]));
						if (keycounts[key]) keycounts[key]++;
						else (keycounts[key]) = 1;
					}
				
				var places = xmlDoc.documentElement.getElementsByTagName("Placemark");
				
					for (var i = 0; i < places.length; i++) {
						//If there are no coordinates skip the marker creation
						if (!places[i].getElementsByTagName("coordinates")[0]) {
							continue;
						}
						var points = coords[i].firstChild.nodeValue;
						var pointsArray = points.split(",");
						//Check to see if the lat/lng are set.  If the point element has a lat/lng, then process the data and create the marker...
						if (pointsArray[0] != 0 && pointsArray[1] != 0) {
							var lng = parseFloat(pointsArray[0]);
							var lat = parseFloat(pointsArray[1]);
							//Send the lat/lng to the hash table
							var key  = hash(lng, lat);
							
							//Create the point using lat/lng
							var point = new GLatLng(lat, lng);
							//Get the unique id number for the record...
							idnumber = parseInt(places[i].getAttribute("id"));
							clickId = 'click' + idnumber;
							
							// Variables for html from xml
							var titleElement = places[i].getElementsByTagName("name")[0];
								//But, need to check to see if the element has a node value...
								if (!titleElement.firstChild) {
									continue;
								}
								else {
									var title = places[i].getElementsByTagName("name")[0].firstChild.nodeValue;
								}
							var desc  = places[i].getElementsByTagName("description")[0].firstChild.nodeValue;
							var saoUrl = places[i].getElementsByTagName("name")[0].getAttribute("url");
							
							// html for the info window
							var ihtml = '<table width="100%" border="0" cellspacing="0" cellpadding="4">';
								ihtml +=    '<tr><td class="title"><b><a href="'+saoUrl+'" target="_blank">' + title +'</a></b></td></tr>';
								ihtml +=    '<tr><td>'+desc+'</td></tr>';
								ihtml +=    '<tr><td><img src="http://maps.google.com/staticmap?center='+lat+','+lng+'&zoom=13&size=256x100&markers='+lat+','+lng+',green&maptype=mobile&key='+mapKey+'"</td></tr>';
								ihtml +=    '</table>';
							
							//TO | Directions html, includes a form...html is added to an array.
							var tohtml =  '<br>Get Directions: <b>To here</b> - <a href="javascript:showDir(' + idnumber +',\'from\')">From here</a>';
								tohtml +=   '<br>Start Address:<form action="http://maps.google.com/maps" method="get" target="_blank">';
								tohtml +=   '<input type="text" size="30" maxlength="30" name="saddr" value="" /><br>';
								tohtml +=   '<input type="submit" value="Get Directions" style="font-size:10px">';
								tohtml +=   '<input type="hidden" name="daddr" value="' + lat + ',' + lng + '(' + title + ')' +'"/></form>';
								tohtml += '<a href="javascript: findMarker(\''+ idnumber + '\')" ';
								tohtml += 'style="font-size:9px; color:#6666CC">&lt;&lt; Back</span>';

							
							//FROM | Format the concatenated html and add to the array
							tohtml = '<div style="overflow:auto; max-height:306px;">' + ihtml + tohtml + '</div>';
					        dirTo[idnumber] = tohtml;
						   
							//FROM | Directions html, includes a form...html is added to an array.
							var fromhtml =  '<br>Get Directions: <a href="javascript:showDir(' + idnumber +',\'to\')">To here</a> - <b>From here</b>';
						        fromhtml += '<br>End Address:<form action="http://maps.google.com/maps" method="get"" target="_blank">';
						        fromhtml += '<input type="text" size="30" maxlength="30" name="daddr" value="" /><br>';
								fromhtml += '<input type="submit" value="Get Directions" style="font-size:10px">';
								fromhtml += '<input type="hidden" name="saddr" value="' + lat + ',' + lng + '(' + title + ')' +'"/></form>';
								fromhtml += '<a href="javascript: findMarker(\''+ idnumber + '\')" ';
								fromhtml += 'style="font-size:9px; color:#6666CC">&lt;&lt; Back</span>';
							
								//FROM | Format the concatenated html and add to the array
								fromhtml = '<div style="overflow:auto; max-height:306px;">' + ihtml + fromhtml + '</div>';
						        dirFrom[idnumber] = fromhtml;
							
							//NEARBY | Nearby html, includes a form...html is added to an array.
							var nearbyhtml =  '<br>Search Nearby: <span style="color:#666666">e.g., "coffee"</span>';
						        nearbyhtml += '<br><form action="http://maps.google.com/maps" method="get"" target="_blank">';
						        nearbyhtml += '<input type="text" size="30" maxlength="30" name="q" value="" /><br>';
								nearbyhtml += '<input type="submit" value="Search" style="font-size:10px">';
								nearbyhtml += '<input type="hidden" name="near" value="' + lat + ',' + lng + '(' + title + ')' +'"/></form>';
								nearbyhtml += '<a href="javascript: findMarker(\''+ idnumber + '\')" ';
								nearbyhtml += 'style="font-size:9px; color:#6666CC">&lt;&lt; Back</span>';
							
								//FROM | Format the concatenated html and add to the array
								nearbyhtml = '<div style="overflow:auto; max-height:306px;">' + ihtml + nearbyhtml + '</div>';
						        dirNearby[idnumber] = nearbyhtml;
							
							// Initial direction info link
							var dirhtml = '<br>Get directions: <a href="javascript:showDir(' + idnumber +',\'to\')">';
								dirhtml    += 'To here</a> - <a href="javascript:showDir(' + idnumber +',\'from\')">From here</a>';
								dirhtml    += ' - <a href="javascript:nearby(' + idnumber + ')">Search Nearby</a>';
								dirhtml    += '<br/><a href="javascript:saozoomto(' + idnumber + ', \'in\')"> Zoom In</a> - ';
								dirhtml    += '<a href="javascript:saozoomto(' + idnumber + ', \'out\')"> Zoom Out</a> - ';
								dirhtml    += '<a href="javascript:saozoomStreet(' + idnumber + ', \'out\')"> Street Level</a>';
						        ihtml = ihtml + dirhtml;
					
							var mhtml = "";
							
							//If there are multiple listings at the same location then add the key to the nodes array and the ihtml string to the nodehtmls array.
							if (keycounts[key] != 1 && !nodes[key]) {
								nodes.push(key);
								nodehtmls.push('<div onClick = highlight("' + clickId + '") style="cursor: pointer; padding:3px; margin:3px; border: 1px solid #999999;">'+ ihtml +'</div>');
							}
						
							//Add the mhtml string from the array to the mhtml variable.  The mhtml variable will be reset after each iteration of the items.length for loop;
							for (var q = 0; q < nodes.length; q++) {
								if (nodes[q] == key) {
								mhtml += nodehtmls[q];	
								} 
							}
							
							//Increase the counter by 1
							cnum=cnum+1;
							
							//Create a marker for each item and pass the process to the loader...
							var marker = createMarker(point, title, mhtml, ihtml, clickId, saoUrl);
							
							//Skip the marker creation if marker already exists...
							if (existingMarkers[idnumber]) {
								continue;
							}
							
							existingMarkers[idnumber] = marker;

							//Send data to loader if showLoad is true...otherwise, call addPoints function directly
							if (showLoad == true) {
								loader.add(i, addPoints, marker);
							}
							else {
								addPoints(marker);
							}
								
						}
					}	
						  	//Upon finishing, show the total number of records and the clickable telephone number in the resultpanel
							document.getElementById("resultpanel").innerHTML = '<img src="companies-header.png" alt="Companies" /><br/>Click on an item below to see the member listing on the map:<br>('+ kmlcount +' total records)<br><table style="width:100%;" cellspacing="0">' + sidehtml + '</table>';
							
							//Start progress bar if showLoad is true
							if (showLoad == true) {
								loader.execute();
							}				
			});
		
		//Get the map center
		var saomapCenter = map.getCenter();
		//The saomapLat and saomapLng variables are updated to reflect the new map center.  Used for comparison in event listener for moveend event.
		saomapLat = saomapCenter.lat();
		saomapLng = saomapCenter.lng();
		
		} //end loadData function...
}

//If the browser is not Javascript enabled/capable, then let the user know that the map cannot be displayed....
else {
document.getElementById("map").innerHTML = 'Sorry, your browser does not support the mapping API';
}

//]]>