GPXParser.prototype.AddTrackpointsToMap = function ()
{
	var tracks = this.xmlDoc.documentElement.getElementsByTagName("trk");
	//var latlngbounds = new GLatLngBounds();
        var trackNames = [];	
        
	for (var i=0; i < tracks.length; i++){
	  var name = i;
	  if(tracks[i].getElementsByTagName("name")[0]){
	    name = tracks[i].getElementsByTagName("name")[0].firstChild.nodeValue
	  }
	  
	  trackNames.push(name);
	  
	  // Display only tracks in the displayed_track list, ignore others
	  if(displayed_tracks){
	    var found = false;
	    for(var j = 0; j < displayed_tracks.length; j++){
	      if(i == displayed_tracks[j]){
	        found = true;
	        break;
	      }
	    }
	    
	    if(!found)continue;
	  }
	        
	        
          this.AddTrackToMap(tracks[i], this.trackcolour, this.trackwidth);
	  //var tracklatlngbounds = this.AddTrackToMap(tracks[i], this.trackcolour, this.trackwidth);
	  //latlngbounds.extend(tracklatlngbounds.getSouthWest());
	  //latlngbounds.extend(tracklatlngbounds.getNorthEast());
	}
	
	displayTrackNames(trackNames);

	// All methods that add items to the map return the bounding box of what they added.
	//return latlngbounds;
}


		function onLoad(file)
		{

		
			MyMap = new GMap2(document.getElementById("map"));
			
			//MyMap.addControl(new GLargeMapControl());
			//MyMap.addControl(new GMapTypeControl());
			MyMap.setUIToDefault();
      MyMap.addMapType(G_NORMAL_MAP);
			LoadGPXFileIntoGoogleMap(MyMap, file);
			
			
	        }

GPXParser.prototype.AddImageMarkersToMap = function(){
  //if(imageTimes.length < 1)return;
  
  var trackPoints = this.xmlDoc.documentElement.getElementsByTagName("trkpt");
 
  for(var i = 1; i < trackPoints.length; i++){
    
    for(filename in imageTimes){
                 
      if(imageTimes[filename] != null){                    
        //var previous_msmt_time = getMilliseconds(trackPoints[i-1].childNodes[3].firstChild.nodeValue);
        var previous_msmt_time = getMilliseconds(trackPoints[i-1].getElementsByTagName("time")[0].firstChild.nodeValue);
        var msmt_time = getMilliseconds(trackPoints[i].getElementsByTagName("time")[0].firstChild.nodeValue);
        var image_time = imageTimes[filename]*1000;
        
        //if(image_time < msmt_time && image_time >= previous_msmt_time){
        if(image_time < msmt_time){ 
                 
          // Which measurement is the image time closest to?                      
          var imageLatLon = null;
                      
          if(msmt_time - image_time > image_time - previous_msmt_time){
            var previousLon = parseFloat(trackPoints[i-1].getAttribute("lon"));
            var previousLat = parseFloat(trackPoints[i-1].getAttribute("lat"));                       
            imageLatLon = new GLatLng(previousLat, previousLon);
          }else{
            var lon = parseFloat(trackPoints[i].getAttribute("lon"));
            var lat = parseFloat(trackPoints[i].getAttribute("lat"));             
            imageLatLon = new GLatLng(lat, lon);
          }
                            
          this.addMarker(filename, imageLatLon);    
          imageTimes[filename] = null;
        }
      }
    }
  }
}

function updateMarkers(filename){
      
  if(parser.clickMarker != null){
    MyMap.removeOverlay(parser.clickMarker);
  }
  
  if(!parser.markers[filename])return;      
        
  var lat = parser.markers[filename].getPoint().lat();
  var lng = parser.markers[filename].getPoint().lng();     
  
  parser.clickMarker = new GMarker(new GLatLng(lat, lng), {icon:parser.myIcon});
  MyMap.addOverlay(parser.clickMarker);
}



///////////////////////////////////////////////////////////////////////////////
// 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 this.
//
// 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/
//
///////////////////////////////////////////////////////////////////////////////
var MyMap;

function updateDisplayedTracks(checkbox){
  var elements = this.document.forms.trackNameForm.elements;
 
  var new_displayed_tracks = [];
  
  var j = 0;
  var k = 0;
  var atLeastOneChecked = false;
  for(var i = 0; i < elements.length; i++){
    
    if(elements[i].type == "checkbox"){     
      if(elements[i].checked){
        atLeastOneChecked  = true;
        
        new_displayed_tracks[j] = k;
        
        j++;
      }
      k++;
    }
  }
  
  if(atLeastOneChecked){
    displayed_tracks = new_displayed_tracks;
  }
      
  MyMap.clearOverlays();
  parser.CenterAndZoom(G_NORMAL_MAP); 
  parser.AddTrackpointsToMap();						
 
  
}

		function LoadGPXFileIntoGoogleMap(map, filename)
		{
			// Remove any existing overlays from the map.
			map.clearOverlays();

			var request = GXmlHttp.create();
			request.open("GET", filename, true);
			request.onreadystatechange = function()
			{
				if (request.readyState == 4)
				{
                               
					parser = new GPXParser(request.responseText, map);
					parser.SetTrackColour("#ff0000");					
					parser.SetTrackWidth(5);												
					parser.SetMinTrackPointDelta(0.000065);				
					parser.CenterAndZoom(G_NORMAL_MAP); 
					parser.AddTrackpointsToMap();	
					parser.AddImageMarkersToMap();					
					//parser.AddWaypointsToMap();
					parser.loadMiniMap();
					parser.createCharts();
					updateMarkers(firstImage);
					
				}
			}
			request.send(null);
		}

	        
GPXParser.prototype.loadMiniMap = function(){
      if (GBrowserIsCompatible()) {
        var minimap = new GMap2(document.getElementById("miniMap"));
        var point = new GLatLng(this.centerlat, this.centerlon);
        minimap.setCenter(point, 4);
        var marker = new GMarker(point);
        minimap.addOverlay(marker);
      }

   }
function GPXParser(xmlData, map)
{
	this.xmlDoc = GXml.parse(xmlData);
	this.map = map;
	//this.markerManager = new GMarkerManager(map);
	this.markers = [];
	this.markerOptions = [];

	this.trackcolour = "#ff00ff"; // red
	this.trackwidth = 5;
	this.mintrackpointdelta;
	//this.centerlat;
	//this.centerlon;
	this.clickMarker = null;
	
        this.custIcon = new GIcon(G_DEFAULT_ICON);
        this.custIcon.iconSize = new GSize(32, 64);
        this.custIcon.shadowSize = new GSize(0, 0);
        this.custIcon.iconAnchor = new GPoint(16, 64);
        this.myIcon = new GIcon(this.custIcon, 'marker.png');

}



// Set the colour of the track line segements.
GPXParser.prototype.SetTrackColour = function(colour)
{
	this.trackcolour = colour;
}

// Set the width of the track line segements
GPXParser.prototype.SetTrackWidth = function(width)
{
	this.trackwidth = width;
}

// Set the minimum distance between trackpoints.
// Used to cull unneeded trackpoints from map.
GPXParser.prototype.SetMinTrackPointDelta = function(delta)
{
	this.mintrackpointdelta = delta;
}

GPXParser.prototype.TranslateName = function(name)
{
	if (name == "wpt")
	{
		return "Waypoint";
	}
	else if (name == "trkpt")
	{
		return "Track Point";
	}
}


GPXParser.prototype.CreateMarker = function(point)
{
	var lon = parseFloat(point.getAttribute("lon"));
	var lat = parseFloat(point.getAttribute("lat"));
	var html = "";

	if (point.getElementsByTagName("html").length > 0)
	{
		for (i=0; i<point.getElementsByTagName("html").item(0).childNodes.length; i++)
		{
			html += point.getElementsByTagName("html").item(0).childNodes[i].nodeValue;
		}
	}
	else
	{
		// Create the html if it does not exist in the point.
		html = "<b>" + this.TranslateName(point.nodeName) + "</b><br>";
		var attributes = point.attributes;
		var attrlen = attributes.length;
		for (i=0; i<attrlen; i++)
		{
			html += attributes.item(i).name + " = " + attributes.item(i).nodeValue + "<br>";
		}

		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].nodeName + " = " + children[i].firstChild.nodeValue + "<br>";
			}
		}
	}

	var marker = new GMarker(new GLatLng(lat,lon));
	GEvent.addListener(marker, "click",
		function()
		{
			marker.openInfoWindowHtml(html);
		}
	);

	this.map.addOverlay(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);
}

function getMilliseconds(time){
  var date = time.split("T")[0];
  var year = date.split("-")[0];
  var month = date.split("-")[1]-1;
  var day = date.split("-")[2];
  var clock = time.split("T")[1];
  var hour = clock.split(":")[0];
  var min = clock.split(":")[1];
  var sec = clock.split(":")[2].substr(0, 2);
  return new Date(year,month,day,hour,min,sec).getTime();
}

GPXParser.prototype.AddTrackSegmentToMap = function(trackSegment, colour, width)
{
	//var latlngbounds = new GLatLngBounds();

	var trackpoints = trackSegment.getElementsByTagName("trkpt");
	if (trackpoints.length == 0)
	{
		return; //latlngbounds;
	}

	var pointarray = [];
	

	// process first point
	var lastlon = parseFloat(trackpoints[0].getAttribute("lon"));
	var lastlat = parseFloat(trackpoints[0].getAttribute("lat"));
	var latlng = new GLatLng(lastlat,lastlon);
	pointarray.push(latlng);
	//latlngbounds.extend(latlng);

	// Create a marker at the begining of each track segment
	//this.CreateMarker(trackpoints[0]);
	
	for (var i=1; i < trackpoints.length; i++){	
    
    var lon = parseFloat(trackpoints[i].getAttribute("lon"));
	  var lat = parseFloat(trackpoints[i].getAttribute("lat"));
		
		// Verify that this is far enough away from the last point to be used.
		//var latdiff = lat - lastlat;
		//var londiff = lon - lastlon;
				
		
		//if(Math.sqrt(latdiff*latdiff + londiff*londiff) > this.mintrackpointdelta ){
			
			latlng = new GLatLng(lat,lon);
			pointarray.push(latlng);
		//}
		
		//lastlon = lon;
		//lastlat = lat;
		           
	}
	
	//document.getElementById('AdSense').innerHTML = q;
	var polyline = new GPolyline(pointarray, colour, width);

	this.map.addOverlay(polyline);

	// All methods that add items to the map return the bounding box of what they added.
	//return latlngbounds;
}

GPXParser.prototype.addMarker = function(filename, position){
  
  var marker = new GMarker(position);

  GEvent.addListener(marker, "click", function(){
    updateMarkers(filename);
    loadmainImage(filename);
  });
	             
  this.map.addOverlay(marker);
  this.markers[filename] = marker;
  marker.setImage("mm_20_blue.png");   
  
}

GPXParser.prototype.createCharts = function(){
  var speedChartData = [];
  var elevationChartData = [];
  
  var trkpts = this.xmlDoc.documentElement.getElementsByTagName("trkpt");
  
  var lon1 = parseFloat(trkpts[0].getAttribute("lon"));
	var lat1 = parseFloat(trkpts[0].getAttribute("lat"));
  var time1 = getMilliseconds(trkpts[0].getElementsByTagName("time")[0].firstChild.nodeValue);
  
  var j = 0;
  var mins = 0;
  
  for (var i=1; i < trkpts.length; i++){
  		
      var lon2 = parseFloat(trkpts[i].getAttribute("lon"));
	    var lat2 = parseFloat(trkpts[i].getAttribute("lat"));
      var time2 = getMilliseconds(trkpts[i].getElementsByTagName("time")[0].firstChild.nodeValue);
	    
	    var dist = (3958*3.1415926*Math.sqrt((lat2-lat1)*(lat2-lat1) + Math.cos(lat2/57.29578)*Math.cos(lat1/57.29578)*(lon2-lon1)*(lon2-lon1))/180);
	    var durationHours = (time2-time1)/1000/3600;
	    
	    var speed = 0;
	    
	    if(durationHours > 0){
	      speed = Math.round(100*dist/durationHours)/100;
	    }
	    
	    if((activity == 'Cycling' && speed < 30.0) || (activity == 'Paddling' && speed < 10.0) ||
	       (activity == 'Hiking' && speed < 10.0) || (activity == 'Driving' && speed < 90.0)){
	    	
	    	var ele = parseFloat(trkpts[i].getElementsByTagName("ele")[0].firstChild.nodeValue);
	    	
	    	speedChartData[j] = [mins, speed];
        elevationChartData[j] = [mins, Math.round(100*ele*3.2808399)/100];
	    	
	    	j++;
	    }
      
      lon1 = lon2;
      lat1 = lat2;
      time1 = time2;
      mins += durationHours*60;
  }
  
	speedChart.setDataArray(speedChartData);
	speedChart.draw();
	
	elevationChart.setDataArray(elevationChartData);
	elevationChart.draw();
  
}

GPXParser.prototype.AddTrackToMap = function(track, colour, width)
{
	var segments = track.getElementsByTagName("trkseg");
	
	//var latlngbounds = new GLatLngBounds();
	for (var i=0; i < segments.length; i++)
	{
		var segmentlatlngbounds = this.AddTrackSegmentToMap(segments[i], colour, width);
		//this.AddTrackSegmentToMap(segments[i], colour, width);
		//latlngbounds.extend(segmentlatlngbounds.getSouthWest());
		//latlngbounds.extend(segmentlatlngbounds.getNorthEast());
	}

	// All methods that add items to the map return the bounding box of what they added.
	//return latlngbounds;
}

// Center and Zoom
GPXParser.prototype.CenterAndZoom = function (maptype)
{

	var pointlist = new Array("trkpt", "wpt");
	var minlat = 0;
	var maxlat = 0;
	var minlon = 0;
	var maxlon = 0;
	
	var tracks = this.xmlDoc.documentElement.getElementsByTagName("trk");
	
        for (var i=0; i< pointlist.length; i++)
	{

		// Center the map and zoom on the given segment.
		//var trackpoints = this.xmlDoc.getElementsByTagName(pointlist[i]);
		var trackpoints = new Array();
	        
	        if(displayed_tracks){
	          for (var j=0; j< displayed_tracks.length; j++){
	            var displayedTrackIndex = displayed_tracks[j];
	            //alert(displayedTrackIndex );
	            var track = tracks[displayedTrackIndex].getElementsByTagName(pointlist[i]);
	            trackpoints.push(track);
	          }
	        }else{ // Display all tracks in the GPX file
	          for (var j=0; j< tracks.length; j++){
	            var track = tracks[j].getElementsByTagName(pointlist[i]);
	            trackpoints.push(track);
	          }
	        }
	        
		// If the min and max are uninitialized then initialize them.
		if ( (trackpoints.length > 0) && (minlat == maxlat) && (minlat == 0) )
		{
		  var t = trackpoints[trackpoints.length-1];		  
		  
			minlat = parseFloat(trackpoints[0][0].getAttribute("lat"));
			maxlat = parseFloat(t[t.length-1].getAttribute("lat"));
			minlon = parseFloat(trackpoints[0][0].getAttribute("lon"));
			maxlon = parseFloat(t[t.length-1].getAttribute("lon"));
		}

		for (var i=0; i < trackpoints.length; i++){
		  var t = trackpoints[i];
		  
		  for (var j=0; j < t.length; j++){
			var lon = parseFloat(t[j].getAttribute("lon"));
			var lat = parseFloat(t[j].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(49.327667, -122.942333), 14, G_NORMAL_MAP);
		return;
	}

	// Center around the middle of the points
	this.centerlon = (maxlon + minlon) / 2;
	this.centerlat = (maxlat + minlat) / 2;

	var bounds = new GLatLngBounds(new GLatLng(minlat, minlon), new GLatLng(maxlat, maxlon));

	this.map.setCenter(new GLatLng(this.centerlat, this.centerlon), this.map.getBoundsZoomLevel(bounds), maptype);
}

GPXParser.prototype.CenterAndZoomToLatLngBounds = function (latlngboundsarray)
{
	var boundingbox = new GLatLngBounds();
	for (var i=0; i<latlngboundsarray.length; i++)
	{
		if (!latlngboundsarray[i].isEmpty())
		{
			boundingbox.extend(latlngboundsarray[i].getSouthWest());
			boundingbox.extend(latlngboundsarray[i].getNorthEast());
		}
	}

	var centerlat = (boundingbox.getNorthEast().lat() + boundingbox.getSouthWest().lat()) / 2;
	var centerlng = (boundingbox.getNorthEast().lng() + boundingbox.getSouthWest().lng()) / 2;
	this.map.setCenter(new GLatLng(centerlat, centerlng), this.map.getBoundsZoomLevel(boundingbox));
}

function displayTrackNames(trackNames){
			var tracks = document.getElementById("tracks");
			if(tracks != null){
			  var trackHtml = "<form method=POST name=trackNameForm action=\"createTrip.php\">";
			  trackHtml += "<input type=hidden name=tripId value="+tripId+">";
			  trackHtml += "<input type=hidden name=mode value=create>";
			  trackHtml += "<input type=hidden name=file value=\""+filename+"\">";
			  trackHtml += "<table border=0>";
			  
			  trackHtml += "<tr>";
			  trackHtml += "<td colspan=2>";
			  trackHtml += "<b>Display Tracks:</b>";
			  trackHtml += "</td>";
			  trackHtml += "</tr>";
			  
			  
			  for(var i = 0; i < trackNames.length; i++){
			    trackHtml += "<tr>";
			    trackHtml += "<td>";
	                    
	                    var found = false;
	                    
	                    if(displayed_tracks){
	                                         
	                      for(var j = 0; j < displayed_tracks.length; j++){
	                        if(i == displayed_tracks[j]){
			          trackHtml += "<input type=checkbox onClick=\"updateDisplayedTracks(this);\" name=track[] checked value=\""+i+"\">";
			          found = true;
			          break;
			        }			        
			      }
			    }else{
			      trackHtml += "<input type=checkbox onClick=\"updateDisplayedTracks(this);\" checked name=track[] value=\""+i+"\">";
			    }
			    
		            if(displayed_tracks && !found){
			      trackHtml += "<input type=checkbox onClick=\"updateDisplayedTracks(this);\" name=track[] value=\""+i+"\">";			          
			    }

			    
			    trackHtml += "</td>";
			    trackHtml += "<td>";
			    trackHtml += trackNames[i];
			    trackHtml += "</td>";
			    trackHtml += "</tr>";
			  }
			  trackHtml += "<tr>";
			  trackHtml += "<td colspan=2>";
			  trackHtml += "<input type=submit value=Done>";
			  trackHtml += "</td>";
			  trackHtml += "</tr>";
			  trackHtml += "</table>";
			  trackHtml += "</form>";
			  tracks.innerHTML = trackHtml;
			}
}

GPXParser.prototype.AddWaypointsToMap = function ()
{
	var waypoints = this.xmlDoc.documentElement.getElementsByTagName("wpt");
	//var latlngbounds = new GLatLngBounds();

	for (var i=0; i < waypoints.length; i++)
	{
		this.CreateMarker(waypoints[i]);
		//var waypointlatlngbounds = this.CreateMarker(waypoints[i]);
		//latlngbounds.extend(waypointlatlngbounds.getSouthWest());
		//latlngbounds.extend(waypointlatlngbounds.getNorthEast());
	}

	// All methods that add items to the map return the bounding box of what they added.
	//return latlngbounds;
}
