///////////////////////////////////////////////////////////////////////////////
// loadgpx.4.js
//
// Javascript object to load GPX-format GPS data into Google Maps.
//
// Copyright (C) 2006 Kaz Okuda (http://notions.okuda.ca)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
//
// If you use this script or have any questions please leave a comment
// at http://notions.okuda.ca/geotagging/projects-im-working-on/gpx-viewer/
// A link to the GPL license can also be found there.
//
///////////////////////////////////////////////////////////////////////////////
//
// History:
//    revision 1 - Initial implementation
//    revision 2 - Removed LoadGPXFileIntoGoogleMap and made it the callers
//                 responsibility.  Added more options (colour, width, delta).
//    revision 3 - Waypoint parsing now compatible with Firefox.
//    revision 4 - Upgraded to Google Maps API version 2.  Tried changing the way
//               that the map calculated the way the center and zoom level, but
//               GMAP API 2 requires that you center and zoom the map first.
//               I have left the bounding box calculations commented out in case
//               they might come in handy in the future.
//
// Author: Kaz Okuda
// URI: http://notions.okuda.ca/geotagging/projects-im-working-on/gpx-viewer/
//
///////////////////////////////////////////////////////////////////////////////

// Create our base marker icon 
var icons = new Array();
icons[""] = new GIcon(); 
icons[""].image = "http://www.google.com/mapfiles/marker.png"; 
icons[""].shadow="http://www.google.com/mapfiles/shadow50.png"; 
icons[""].iconSize=new GSize(20, 34); 
icons[""].shadowSize=new GSize(37, 34); 
icons[""].iconAnchor=new GPoint(9,34); 
icons[""].infoWindowAnchor=new GPoint(9,2); 
icons[""].infoShadowAnchor=new GPoint(18,25); 
icons[""].printImage="http://www.google.com/mapfiles/markerie.gif"; 
icons[""].mozPrintImage="http://www.google.com/mapfiles/markerff.gif"; 
icons[""].printShadow="http://www.google.com/mapfiles/dithshadow.gif"; 
icons[""].transparent="http://www.google.com/mapfiles/markerTransparent.png";
icons[""].imageMap=[9,0,6,1,4,2,2,4,0,8,0,12,1,14,2,16,5,19,7,23,8,26,9,30,9,34,11,34,11,30,12,26,13,24,14,21,16,18,18,16,20,12,20,8,18,4,16,2,15,1,13,0]; 

icons["tiny"] = new GIcon(); 
icons["tiny"].image = "http://labs.google.com/ridefinder/images/mm_20_yellow.png"; 
icons["tiny"].shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png"; 
icons["tiny"].iconSize = new GSize(12, 20); 
icons["tiny"].shadowSize = new GSize(22, 20); 
icons["tiny"].iconAnchor = new GPoint(6, 20); 
icons["tiny"].infoWindowAnchor = new GPoint(5, 1); 
icons["tiny"].imageMap = [4,0,0,4,0,7,3,11,4,19,7,19,8,11,11,7,11,4,7,0]; 
icons["tiny"].transparent = "markerIcons/mm_20_transparent.png";

var tinyIcons = new Array();
tinyIcons.push(icons["tiny"]);

var green = new GIcon(icons["tiny"]);
green.image = "http://labs.google.com/ridefinder/images/mm_20_green.png";
tinyIcons.push(green);

var blue = new GIcon(icons["tiny"]);
blue.image = "http://labs.google.com/ridefinder/images/mm_20_blue.png";
tinyIcons.push(blue);

var red = new GIcon(icons["tiny"]);
red.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
tinyIcons.push(red);

var purple = new GIcon(icons["tiny"]);
purple.image = "http://labs.google.com/ridefinder/images/mm_20_purple.png";
tinyIcons.push(purple);

var white = new GIcon(icons["tiny"]);
white.image = "http://labs.google.com/ridefinder/images/mm_20_white.png";
tinyIcons.push(white);

var gray = new GIcon(icons["tiny"]);
gray.image = "http://labs.google.com/ridefinder/images/mm_20_gray.png";
tinyIcons.push(gray);


var projectMarkers = new Array();
var markers = new Array();

function numberedIcon(iconNumber) {
	var number;
	if (isNaN(parseInt(iconNumber))) {
	
	  number = "";
	} else if (!isNaN(parseInt(iconNumber)) && ((iconNumber < 0) || (iconNumber > 99))) {
	  number = "";
	} else if ((typeof(iconNumber)=="undefined") || (iconNumber==null)) { 
	  number = "" 
	} else { 
	  number = iconNumber; 
	}
	
	if (!icons[iconNumber]) {
		var icon = new GIcon(icons[""]);
		icon.image = "markerIcons/marker" + number + ".png";
		icons[iconNumber]=icon;
	}
/*	if (iconNumber == 1) { return icons["tiny"]; }
	if (iconNumber == 2) {
		return blue;
	}
*/	return icons[iconNumber];
}

function GPXParser(xmlDoc, map)
{
	this.xmlDoc = xmlDoc;
	this.map = map;
}

GPXParser.prototype.CreateMarker = function(point)
{
	var lon = parseFloat(point.getAttribute("lon"));
	var lat = parseFloat(point.getAttribute("lat"));
	var count = parseInt(point.getAttribute("count"));
	var country = point.getAttribute("country");
	var html = "";
	var lon_p, lat_p, name_p, node_p, projectMarker;

	if (point.hasChildNodes)
	{
		var children = point.childNodes;
		var childrenlen = children.length;
		for (i=0; i<childrenlen; i++)
		{
			// Ignore empty nodes
			if (children[i].nodeType != 1) continue;
			html += children[i].firstChild.firstChild.nodeValue + "<br>";
			node_p = children[i];
			name_p = country + ": " + node_p.firstChild.firstChild.nodeValue;
			lon_p = parseFloat(node_p.getAttribute("lon"));
			lat_p = parseFloat(node_p.getAttribute("lat"));
			//html += children[i].nodeName + " = " + children[i].firstChild.nodeValue + "<br>";

			projectMarker = new GMarker(new GLatLng(lat_p,lon_p), {icon:red, title:name_p.replace(/(<([^>]+)>)/ig,"")});
			projectMarkers.push(projectMarker);
		}
	}

	html = "<div style='max-height:200px; overflow:auto'>" + html + "</div>";
	var title = country + " (" + count + ")";
	html = "<b>"+title+"</b><br/>" + html;

	var marker = new GMarker(new GLatLng(lat,lon), {icon:numberedIcon(count), title:title});
	GEvent.addListener(marker, "click",
		function()
		{
			this.openInfoWindowHtml(html);
		}
	);

	return marker;

	// All methods that add items to the map return the bounding box of what they added.
	//var latlng = new GLatLng(lat,lon);
	//return new GLatLngBounds(latlng,latlng);
}

GPXParser.prototype.CreateCategoryMarker = function(point, country, html, category)
{
	node_p = point;
	name_p = country + ": " + node_p.firstChild.firstChild.nodeValue;
	lon_p = parseFloat(node_p.getAttribute("lon"));
	lat_p = parseFloat(node_p.getAttribute("lat"));
	icon_p = parseInt(node_p.childNodes[category].getAttribute("icon"));
	
	var marker = new GMarker(new GLatLng(lat_p,lon_p), {icon:tinyIcons[icon_p-1], title:name_p});
	GEvent.addListener(marker, "click",
		function()
		{
			this.openInfoWindowHtml(html);
		}
	);
	return marker;
}

GPXParser.prototype.CenterAndZoom = function (markerList, maptype)
{

	var pointTypeList = new Array("marker");
	var minlat = 0;
	var maxlat = 0;
	var minlon = 0;
	var maxlon = 0;

	for (var pointType=0; pointType < pointTypeList.length; pointType++)
	{

		// Center the map and zoom on the given markers.
		var pointList = markerList.getElementsByTagName(pointTypeList[pointType]);

		// If the min and max are uninitialized then initialize them.
		if ( (pointList.length > 0) && (minlat == maxlat) && (minlat == 0) )
		{
			minlat = parseFloat(pointList[0].getAttribute("lat"));
			maxlat = parseFloat(pointList[0].getAttribute("lat"));
			minlon = parseFloat(pointList[0].getAttribute("lon"));
			maxlon = parseFloat(pointList[0].getAttribute("lon"));
		}

		for (var i=0; i < pointList.length; i++)
		{
			var lon = parseFloat(pointList[i].getAttribute("lon"));
			var lat = parseFloat(pointList[i].getAttribute("lat"));

			if (lon < minlon) minlon = lon;
			if (lon > maxlon) maxlon = lon;
			if (lat < minlat) minlat = lat;
			if (lat > maxlat) maxlat = lat;
		}
	}

	if ( (minlat == maxlat) && (minlat = 0) )
	{
		this.map.setCenter(new GLatLng(40.704564,-74.014412), 4, maptype);
		return;
	}

	// Center around the middle of the points
	var centerlon = (maxlon + minlon) / 2;
	var centerlat = (maxlat + minlat) / 2;

	var bounds = new GLatLngBounds(new GLatLng(minlat, minlon), new GLatLng(maxlat, maxlon));

	this.map.setCenter(new GLatLng(centerlat, centerlon), this.map.getBoundsZoomLevel(bounds), maptype);
}

GPXParser.prototype.AddWaypointsToMap = function (mgr)
{
	var waypoints = this.xmlDoc.documentElement.getElementsByTagName("marker");
	//var latlngbounds = new GLatLngBounds();
	markers = new Array();
	projectMarkers = new Array();

	for (var i=0; i < waypoints.length; i++)
	{
		markers.push(this.CreateMarker(waypoints[i]));
		//this.CreateMarker(waypoints[i]);
		//var waypointlatlngbounds = this.CreateMarker(waypoints[i]);
		//latlngbounds.extend(waypointlatlngbounds.getSouthWest());
		//latlngbounds.extend(waypointlatlngbounds.getNorthEast());
	}
	
	mgr.addMarkers(markers, 1, 9);
	//mgr.addMarkers(projectMarkers, 4, 9);
	mgr.refresh();
	// All methods that add items to the map return the bounding box of what they added.
	//return latlngbounds;
}

GPXParser.prototype.AddCategoriesToMap = function (mgr, category)
{
	var waypoints = this.xmlDoc.documentElement.getElementsByTagName("marker");
	var html, name, cat = "";

	for (var i=0; i < waypoints.length; i++) {
		var lon = parseFloat(waypoints[i].getAttribute("lon"));
		var lat = parseFloat(waypoints[i].getAttribute("lat"));
		var count = parseInt(waypoints[i].getAttribute("count"));
		var country = waypoints[i].getAttribute("country");
		
		if (waypoints[i].hasChildNodes) {
			for (var j=0; j < waypoints[i].childNodes.length; j++) {
				name = waypoints[i].childNodes[j].firstChild.firstChild.nodeValue;
				cat = waypoints[i].childNodes[j].childNodes[category].firstChild.nodeValue;
				html = country + ": " + name + "<br />" + cat ;
				mgr.addMarker(this.CreateCategoryMarker(waypoints[i].childNodes[j], country, html , category), 3, 9);
			}
		}
	}
	mgr.refresh();
}