/*--------------------------------------------------------------------------*/
/*  Western North Carolina GPS Mapper                                       *
 *  (c) 2008 - 2009 Jordan Mitchell - See attributions                      *
 *  All rights reserved.                                                    *
/*--------------------------------------------------------------------------*/

// Settinate these up before...
var map;
var hostServer = 'http://' + window.location.hostname + '/';
var allMarkers = [];

// Set up custom icons
var customIcons = [];
var customIconTypes = new Array('waterfall','peak','overlook','trailhead','hike','ride','campground','picnic','parking','camera','magnify','town');
for(var i=0;i<customIconTypes.length;i++){
  var iconType = customIconTypes[i];
  var urlPrefix = hostServer + '/images/markers/';
  customIcons[iconType] = new GIcon();
  customIcons[iconType].image = urlPrefix + iconType + ".png";
  customIcons[iconType].shadow = urlPrefix + "shadow.png";
  customIcons[iconType].shadowSize = new GSize(52, 29);
  customIcons[iconType].iconAnchor = new GPoint(0, 29);
  customIcons[iconType].infoWindowAnchor = new GPoint(21, 0);
}

// Set up some stock small Google icons
var gIcons = [];
var gIconTypes = new Array('mm_20_green','mm_20_red');
for(var i=0;i<gIconTypes.length;i++){
  var iconType = gIconTypes[i];
  var urlPrefix = hostServer + '/images/markers/';
  gIcons[iconType] = new GIcon();
  gIcons[iconType].image = urlPrefix + iconType + ".png";
  gIcons[iconType].shadow = urlPrefix + "mm_20_shadow.png";
  gIcons[iconType].iconSize    = new GSize(12, 20);
  gIcons[iconType].shadowSize = new GSize(22, 20);
  gIcons[iconType].iconAnchor = new GPoint(6, 20);
  gIcons[iconType].infoWindowAnchor = new GPoint(5, 1);
}

// So now we have gIcons[name] and customIcons[name] to use when creating markers, mmkay?

/* Load specific route onto gmap */
function loadRouteFromDb(id){
  // First update the form
  var url = hostServer + 'ajax_gps.php';
  var pars = 'action=loadRouteData&routeId=' + id;
  var myAjax = new Ajax.Updater('routeDetails', url, {method: 'get', parameters: pars, evalScripts: true});
  // Next put the route on the map
  pars = 'tracks=1&trackId=' + id;
  loadParseGPX('gpx.php?' + pars);
}

// Create a marker with simple info window - no tabs
function createMarker(map, point, html, icon, pointId) {
  var marker = new GMarker(point, icon);
  map.addOverlay(marker);
  GEvent.addListener(marker, "click", function() {
    marker.openInfoWindowHtml(html);
  });
  allMarkers[pointId] = marker;
  return marker;
}

// Create a marker with a tabbed info window
function createMarkerTabs(map, point, tabarray, icon, pointId, pointIsHikeRide, hikeRideId) {
  var marker = new GMarker(point, icon);
  map.addOverlay(marker);
  // If this point denotes a trailhead for a hike/ride and the associated hike/ride
  // has a polyline associated with it
  GEvent.addListener(marker, "click", function() {
    marker.openInfoWindowTabsHtml(tabarray);
    if(pointIsHikeRide && typeof(hikeRidePolylines[hikeRideId]) != 'undefined'){
      hikeRidePolylines[hikeRideId].setStrokeStyle({opacity: 0.8});
      GEvent.addListener(map, "infowindowclose", function() { 
        hikeRidePolylines[hikeRideId].setStrokeStyle({opacity: 0.0});
      }); 
    }
  });
  allMarkers[pointId] = marker;
  return marker;
}

// Create a polyline for a trail. Should be color coded by use.
function createPolylineEnc(polylineStr, polylineLevelsStr, segmentID, html){
  segmentPolylines[segmentID] = new GPolyline.fromEncoded({
    color: '#0000ff',
    weight: 3,
    opacity: 0.8,
    points: polylineStr,
    levels: polylineLevelsStr,
    numLevels: 18,
    zoomFactor: 2,
    clickable: true
  });
  map.addOverlay(segmentPolylines[segmentID]);
  boundsForTrackZoom = segmentPolylines[segmentID].getBounds();
  
  GEvent.addListener(segmentPolylines[segmentID], "mouseover", function(){
    this.setStrokeStyle({color: "#ffff00"});
    this.setStrokeStyle({weight: 6});
  });
  
  GEvent.addListener(segmentPolylines[segmentID], "mouseout", function(){
    this.setStrokeStyle({color: "#0000ff"});
    this.setStrokeStyle({weight: 3});
  });
  
  GEvent.addListener(segmentPolylines[segmentID], "click", function(overlayLatLng){
    map.openInfoWindowHtml(overlayLatLng,html);
  });
  
  return boundsForTrackZoom;
}

// Create a polyline for a hike/ride. Off to begin with. Highlight it when assoc.
// marker is clicked.
function createHRPolyline(polylineStr, polylineLevelsStr, hikeRideId){
  hikeRidePolylines[hikeRideId] = new GPolyline.fromEncoded({
    color: '#ffff00',
    weight: 6,
    opacity: 0.0,
    points: polylineStr,
    levels: polylineLevelsStr,
    numLevels: 18,
    zoomFactor: 2,
    clickable: true
  });
  map.addOverlay(hikeRidePolylines[hikeRideId]);
  boundsForTrackZoom = hikeRidePolylines[hikeRideId].getBounds(); 
  return boundsForTrackZoom;
}

// "Click" a route when you click something else
// (i.e. - a listing in the search results)
// not working right now :(
function routeClick(segmentID) {
  GEvent.trigger(segmentPolylines[segmentID], "click");
}

// Send the map where we want
function navigateMap(lat,lng,zoom){
  map.setCenter(new GLatLng(lat,lng),zoom);
}

// Toggle all the markers on and off
function toggleMarkers(){
  for(var mc = 0; mc < allMarkers.length; mc++)
  {
    currentMarker = allMarkers[mc];
    if (currentMarker.isHidden()) {
      currentMarker.show();
    } else {
      currentMarker.hide();
    }
  }
}

// Toggle a route
function toggleRoute(rteOverlay) {
  if(rteOverlay.supportsHide()){
    if(rteOverlay.isHidden()) {rteOverlay.show();} else {rteOverlay.hide();}
  } else {
    // Figure out how to determine if the polyline is added tothe map and
    // toggle it based on that
  }
}

// Toggle an individual track segment
function toggleSegment(segmentOverlay) {
  if(segmentOverlay.supportsHide())
  {
    if(segmentOverlay.isHidden()) {segmentOverlay.show();} else {segmentOverlay.hide();}
  }
  else
  {
    // Figure out a way to determine if the polyline is added to the map and
    // toggle it based on that
  }
}

/* Setup Google Map object */
function gmapCommon() {
  if(GBrowserIsCompatible()){
  // Create a topo map layer based on the free Terraserver WMS (Web Mapping Service)
    function WMSCreateMap(name, copyright, baseUrl, layer, minResolution, maxResolution, urlArg )
    {
      var tileLayer = new GTileLayer( new GCopyrightCollection( copyright ), minResolution, maxResolution );
      tileLayer.baseUrl = baseUrl;
      tileLayer.layer = layer;
      tileLayer.getTileUrl = WMSGetTileUrl;
      tileLayer.getCopyright = function () { return copyright; };
      var tileLayers = [ tileLayer ];
      return new GMapType( tileLayers, G_SATELLITE_MAP.getProjection(), name, { errorMessage:"Data Not Available" } );
    }
    // Function to retrieve the tile from the Terraserver WMS
    function WMSGetTileUrl( tile, zoom )
    {
      var southWestPixel = new GPoint( tile.x * 256, ( tile.y + 1 ) * 256);
      var northEastPixel = new GPoint( ( tile.x + 1 ) * 256, tile.y * 256);
      var southWestCoords = G_NORMAL_MAP.getProjection().fromPixelToLatLng( southWestPixel, zoom );
      var northEastCoords = G_NORMAL_MAP.getProjection().fromPixelToLatLng( northEastPixel, zoom );
      var bbox = southWestCoords.lng() + ',' + southWestCoords.lat() +
            ',' + northEastCoords.lng() + ',' + northEastCoords.lat();
      return this.baseUrl + '?VERSION=1.1.1&REQUEST=GetMap&LAYERS=' +
            this.layer + '&STYLES=&SRS=EPSG:4326&BBOX=' + bbox +
                  '&WIDTH=256&HEIGHT=256&FORMAT=image/jpeg&BGCOLOR=0xCCCCCC&EXCEPTIONS=INIMAGE';
    }
    // Create the layer
    var WMS_TOPO_MAP = WMSCreateMap( 'Topo', 'Imagery by USGS / Web Service by TerraServer',
      'http://www.terraserver-usa.com/ogcmap6.ashx', 'DRG', 4, 17, 't' );
    var map = new GMap2(document.getElementById("map"));
    map.addMapType(WMS_TOPO_MAP); // Add the topo map
    map.addMapType(G_PHYSICAL_MAP); // Add the physical map
    map.addControl(new GLargeMapControl());
    map.addControl(new GMapTypeControl());
    
    map.enableScrollWheelZoom();
  } // End if browser is compatible
  return map;
} // End gmapCommon function


/************************************************
// Load and parse the GPX file
// Adapted from the GPX Loader for Google Maps
// http://www.obviously.com/gis/gpx_loader.html
// Information about the GPX file format:
// http://www.topografix.com/gpx_manual.asp
/***********************************************/
function loadParseGPX(URL){   
  
  var wptsProcessed = false;
  var trksProcessed = false;
  
  var featureTableHtml = '<h3>Trails</h3>' + 
    '<p>Click trail name for description.</p>' +
    '<table id="trailAttr" class="attrTable" width="100%">' +
    '<thead>' + 
    '<tr><th>Name</th><th>Length</th><th>Difficulty</th><th>Steepness</th><th>Tread Condition</th>' +
    '<th>Blaze Color</th><th>Bikes?</th><th>Horses?</th><th>Accessible?</th><th>Data</th></tr>' +
    '</thead>';
  
  if (GBrowserIsCompatible()) {
    map = gmapCommon();
  }
  
  // Clear the map
  map.clearOverlays();
  allMarkers=[];
  
  // Request the XML file (GPX) using Google's XMLHTTP stuff
  var request = GXmlHttp.create();
  // var URL = "gpx.php?points=1";
  request.open("GET", hostServer + URL, true);
  
  request.onreadystatechange = function() {
    if (request.readyState == 4) {
      var gpxDoc = request.responseXML;
      if( !gpxDoc ) {
        alert("Could not load GPX document " + URL);
      } else if( !gpxDoc.documentElement ) {
        alert("Document " + URL + "\nwas not recognized by the XML loader");
      } else if( gpxDoc.documentElement.tagName != 'gpx' ) {
        alert("This does not appear to be a GPX file.");
      } else { // This does appear to be a GPX document

        map.setCenter(new GLatLng(35.8005, -82.4770), 8, G_PHYSICAL_MAP);

        var boundsForZoomLevel = new GLatLngBounds();
        
        // ***************************************************
        // Process waypoints (<wpt> tags)
        // ***************************************************
        var wpt;
        wpt = gpxDoc.documentElement.getElementsByTagName("wpt")
        if(wpt.length > 0) {
          wptsProcessed = true;
          for (var i = 0; i < wpt.length; i++) {
            pointIsHikeRide = false;
            
            wptLon = parseFloat(wpt[i].getAttribute("lon"));
            wptLat = parseFloat(wpt[i].getAttribute("lat"));
            point = new GPoint(wptLon,wptLat);
            latlng = new GLatLng(wptLat, wptLon);
            boundsForZoomLevel.extend(latlng);
            
            // Get extensions from the <extensions> tag
            element = wpt[i].getElementsByTagName("pointid");
            if( element.length ){
              elePointId = element[0].firstChild.nodeValue;
            } else {
              alert('No point ID found');
            }
            
            // Determine map symbol based on <type> tag
            // Default is small green pin
            myicon = gIcons['mm_20_green'];
            element = wpt[i].getElementsByTagName("type");
            if( element.length ){
              eleType = element[0].firstChild.nodeValue;
              myicon = customIcons[eleType];
            }
            
            // Now, need to build up HTML for tabs and feature table.
            // Array to hold the tabs
            var allTabs = new Array();
            var length;
            
            // Tab 1
            var tab1label = "General";
            var tab1html = '<div style="width:350px">';
            tphoto = "";
            tname = "";
            tdesc = "";
            // Photo and Thumbnail
            element = wpt[i].getElementsByTagName("photo");
            if( element.length ) {
              tphoto = element[0].firstChild.nodeValue;
              tab1html += '<div style="float:right; margin-left: 5px;">' +
                '<a href="' + tphoto + 
                '" rel="lytebox" onclick="myLytebox.start(this, false); return false;">';  
              element = wpt[i].getElementsByTagName("thumb");
              if( element.length ) {
                tthumb = element[0].firstChild.nodeValue;
                tab1html += '<img src="' +
                tthumb + '" style="border:1px solid black;"></a></div>';
              } // If there is a thumb
            } // If there is a photo
            // name
            element = wpt[i].getElementsByTagName("name");
            if( element.length ) {
              tname = element[0].firstChild.nodeValue;
              tab1html += '<h2>' + tname + '</h2>';
            }
            // desc(ription(s))
            element = wpt[i].getElementsByTagName("desc");
            if( element.length ) {
              tdesc = element[0].firstChild.nodeValue;
              tab1html += '<p>' + tdesc + '</p>';
            }            
            element = wpt[i].getElementsByTagName("hikeRidePreviewdesc");
            if( element.length ) {
              tpreviewdesc = element[0].firstChild.nodeValue;
              tab1html += '<p>' + tpreviewdesc + '</p>';
            }
            tab1html += '</div>';
            var tab1 = new GInfoWindowTab(tab1label,tab1html);
            var length = allTabs.push(tab1);
            
            tRelatedHikeRideId = "";
            tname = "";
            tdifficulty = "";
            tlength = "";
            tclimb = "";
            ttread = "";
            tconfiguration = "";
            tpreviewdesc = "";
            turl = "";
            timg = "";
            
            // Tab 2 -- Stats for Best Hikes/Rides
            // Also let's make a control to highlight associated route
            if(eleType == 'hike' || eleType == 'ride'){
              pointIsHikeRide = true;
              var tab2label = "Details";
              var tab2html = '<div style="width:350px">';
              // Build a stats list
              // Would want: name, difficulty, length, climb, tread, and link
              
              element = wpt[i].getElementsByTagName("hikeRideId");
              if( element.length ) {
                tRelatedHikeRideId = element[0].firstChild.nodeValue;
              }
              
              element = wpt[i].getElementsByTagName("hikeRideImg");
              if( element.length ) {
                timg = element[0].firstChild.nodeValue;
                tab2html += '<div style="float:right; margin: 0px 0px 5px 5px; border: 1px solid black">' +
                            '<img src="http://gallery.wncoutdoors.info/images/thumbs/' + timg + '"></div>';
              }
              
              element = wpt[i].getElementsByTagName("hikeRideName");
              if( element.length ) {
                tname = element[0].firstChild.nodeValue;
                tab2html += '<h2>' + tname + '</h2>';
              }
              
              element = wpt[i].getElementsByTagName("hikeRideDifficulty");
              if( element.length ) {
                tdifficulty = element[0].firstChild.nodeValue;
                tab2html += '<p><span style="font-weight:bold">Characteristics:</span><br>'
                         + tdifficulty;
              }
              
              element = wpt[i].getElementsByTagName("hikeRideLength");
              if( element.length ) {
                tlength = element[0].firstChild.nodeValue;
                tab2html += ', ' + tlength + ' miles';
              }
              
              element = wpt[i].getElementsByTagName("hikeRideClimb");
              if( element.length ) {
                tclimb = element[0].firstChild.nodeValue;
                tab2html += ', ' + tclimb;
              }
              
              element = wpt[i].getElementsByTagName("hikeRideTread");
              if( element.length ) {
                ttread = element[0].firstChild.nodeValue;
                tab2html += ', ' + ttread + '</p>';
              }
              
              element = wpt[i].getElementsByTagName("hikeRideConfiguration");
              if( element.length ) {
                tconfiguration = element[0].firstChild.nodeValue;
                tab2html += '<p><span style="font-weight:bold">Configuration:</span><br>'
                         + tconfiguration + '</p>';
              }
                           
              element = wpt[i].getElementsByTagName("hikeRideUrldetails");
              if( element.length ) {
                turl = element[0].firstChild.nodeValue;
                tab2html += '<p><a href="' + turl + '">More Details...</a></p>';
              }

              tab2html += '</div>';
              var tab2 = new GInfoWindowTab(tab2label,tab2html);
              var length = allTabs.push(tab2);
            }
            
            // Tab 2 -- Stats for Trail
            
            // Done making tabs, create marker now
            createMarkerTabs(map, point, allTabs, myicon, elePointId, pointIsHikeRide, tRelatedHikeRideId);
          }
        }
        wpt = [];
        // End processing waypoints
  
        // ***************************************************
        // Process tracks (<trk> tags)
        // ***************************************************
        
        var trk;               // Array containing all <trk></trk> tags in the document
        var trkPosition;       // Stores the current <trk> tag's position in trk
        var trkseg;            // Array containing all <trkseg></trkseg> tags in the current track
        var gPolylineElements; // Just get the polyline for each track segment
        var gPolylineLevelsElements;
        var polylineStr;
        var polylineLevelsStr;
        var polylineEnc;
        var polylineIsHikeRide = false;
        
        var trksegPosition;    // Counter for the # of segments in this track
        var segmentsForTrack;  // Array, one element for each track, containing segments
        var segments;          // Array containing segment ID's in each particular track
        var segmentID = 1;     // Counter to track each segment reached?
        var segPoints;         // Array, containing all the GPoints (lat/lon pairs) for this segment
        var trkpt;             // Array containing all <trkpt> tags in this segment
        var trkptPosition;     // Counter for the # of track points in this segment
                              
        var trkName;           // Object which contains the current track
        var trkNameStr;        // String to hold the name of each track
        var trkDesc;           // Object which contains the current track
        var trkDescStr;        // String to hold the name of each track
        
        boundsForTrackZoom = new GLatLngBounds();
        
        trk = gpxDoc.documentElement.getElementsByTagName("trk");
        if (trk.length > 0) {
          trksProcessed = true;

          segmentPolylines = []; // Storing all non hike/ride segments in one array
          hikeRidePolylines = []; // Storing hike/ride segments in a separate array
          
          // Loop through each <trk></trk> tag in the trk array
          for (trkPosition = 0; trkPosition < trk.length; trkPosition++) {
            polylineIsHikeRide = false;

            // Default color, width, opacity
            tcolor="#7D0000";
            twidth=4;
            topacity=.7;
            trackSegmentHTML = "";
  
            // Extract <name></name> tag for the track itself
            trkNameStr = "";
            trkName = trk[trkPosition].getElementsByTagName("name");
            if( trkName.length ) {
              if( trkName[0].firstChild ) {
                trkNameStr = trkName[0].firstChild.nodeValue;
              }
            }
            
            // Extract <desc></desc> tag for the track itself
            trkDescStr = "";
            trkDesc = trk[trkPosition].getElementsByTagName("desc");
            if( trkDesc.length ) {
              if( trkDesc[0].firstChild ) {
                trkDescStr = trkDesc[0].firstChild.nodeValue;
              }
            }
                          
            // Get each track segment
            trkseg = trk[trkPosition].getElementsByTagName("trkseg");
            if(trkseg.length > 0){
              segmentHTML = "";
              for (trksegPosition = 0; trksegPosition < trkseg.length; trksegPosition++){
                segPoints = [];
                
                // Assemble HTML to send to infoWindow for clicking polylines
                polylineInfoWindowHtml = '<div style="width: 300px;">';
             
                trailTrailid = trk[trkPosition].getElementsByTagName("trailTrailid");
                hikeRideHikerideid = trk[trkPosition].getElementsByTagName("hikeRideHikerideid");
                                
                // Associated trail information                
                trailTrailidStr = "";
                if( trailTrailid.length ) {
                  if( trailTrailid[0].firstChild ) {
                    trailTrailidStr = trailTrailid[0].firstChild.nodeValue;
                                        
                    trailNameStr = "";
                    trailName = trk[trkPosition].getElementsByTagName("trailName");
                    if( trailName.length ) {
                      if( trailName[0].firstChild ) {
                        trailNameStr = trailName[0].firstChild.nodeValue;
                        polylineInfoWindowHtml += '<h2>' + trailNameStr + '</h2>';
                      }
                    }
                    
                    polylineInfoWindowHtml += '<p>';
                    
                    trailDifficultyStr = "";
                    trailDifficulty = trk[trkPosition].getElementsByTagName("trailDifficulty");
                    if( trailDifficulty.length ) {
                      if( trailDifficulty[0].firstChild ) {
                        trailDifficultyStr = trailDifficulty[0].firstChild.nodeValue;
                        polylineInfoWindowHtml += trailDifficultyStr;
                      }
                    }
                    
                    trailSteepnessStr = "";
                    trailSteepness = trk[trkPosition].getElementsByTagName("trailSteepness");
                    if( trailSteepness.length ) {
                      if( trailSteepness[0].firstChild ) {
                        trailSteepnessStr = trailSteepness[0].firstChild.nodeValue;
                        polylineInfoWindowHtml += ', ' + trailSteepnessStr;
                      }
                    }
                    
                    trailTreadconditionStr = "";
                    trailTreadcondition = trk[trkPosition].getElementsByTagName("trailTreadcondition");
                    if( trailTreadcondition.length ) {
                      if( trailTreadcondition[0].firstChild ) {
                        trailTreadconditionStr = trailTreadcondition[0].firstChild.nodeValue;
                        polylineInfoWindowHtml += ', ' + trailTreadconditionStr;
                      }
                    }
                    
                    trailLengthStr = "";
                    trailLength = trk[trkPosition].getElementsByTagName("trailLength");
                    if( trailLength.length ) {
                      if( trailLength[0].firstChild ) {
                        trailLengthStr = trailLength[0].firstChild.nodeValue;
                        polylineInfoWindowHtml += ', ' + trailLengthStr + ' mi';
                      }
                    }
                    
                    trailBlazecolorStr = "";
                    trailBlazecolor = trk[trkPosition].getElementsByTagName("trailBlazecolor");
                    if( trailBlazecolor.length ) {
                      if( trailBlazecolor[0].firstChild ) {
                        trailBlazecolorStr = trailBlazecolor[0].firstChild.nodeValue;
                        polylineInfoWindowHtml += ', ' + trailBlazecolorStr + ' blaze';
                      }
                    }
                    
                    polylineInfoWindowHtml += '<p>';
                    
                    trailHikecommentsStr = "";
                    trailHikecomments = trk[trkPosition].getElementsByTagName("trailHikecomments");
                    if( trailHikecomments.length ) {
                      if( trailHikecomments[0].firstChild ) {
                        trailHikecommentsStr = trailHikecomments[0].firstChild.nodeValue;
                      }
                    }
                    
                    // Omitting comments for now
                    
                    trailBikecommentsStr = "";
                    trailBikecomments = trk[trkPosition].getElementsByTagName("trailBikecomments");
                    if( trailBikecomments.length ) {
                      if( trailBikecomments[0].firstChild ) {
                        trailBikecommentsStr = trailBikecomments[0].firstChild.nodeValue;
                      }
                    }
                    
                    polylineInfoWindowHtml += '<p>Uses: ';
                    
                    trailHikeStr = "";
                    trailHike = trk[trkPosition].getElementsByTagName("trailHike");
                    if( trailHike.length ) {
                      if( trailHike[0].firstChild ) {
                        trailHikeStr = trailHike[0].firstChild.nodeValue;
                        if(trailHikeStr == 1){
                          polylineInfoWindowHtml += 'Hiking';
                        }
                      }
                    }
                                    
                    trailBikeStr = "";
                    trailBike = trk[trkPosition].getElementsByTagName("trailBike");
                    if( trailBike.length ) {
                      if( trailBike[0].firstChild ) {
                        trailBikeStr = trailBike[0].firstChild.nodeValue;
                        if(trailBikeStr == 1){
                         polylineInfoWindowHtml += ', Mountain Biking';
                        }
                      }
                    }
                    
                    trailHorseStr = "";
                    trailHorse = trk[trkPosition].getElementsByTagName("trailHorse");
                    if( trailHorse.length ) {
                      if( trailHorse[0].firstChild ) {
                        trailHorseStr = trailHorse[0].firstChild.nodeValue;
                        if(trailHorseStr == 1){
                         polylineInfoWindowHtml += ', Horseback Riding';
                        }
                      }
                    }
                    
                    trailAccessibleStr = "";
                    trailAccessible = trk[trkPosition].getElementsByTagName("trailAccessible");
                    if( trailAccessible.length ) {
                      if( trailAccessible[0].firstChild ) {
                        trailAccessibleStr = trailAccessible[0].firstChild.nodeValue;
                        if(trailAccessibleStr == 1){
                         polylineInfoWindowHtml += ', Accessible';
                        }
                      }
                    }
                    polylineInfoWindowHtml += '</p>';
                    
                    // Link to download GPX
                    
                    trailRouteidStr = "";
                    trailRouteid = trk[trkPosition].getElementsByTagName("trailRouteid");
                    if( trailRouteid.length ) {
                      if( trailRouteid[0].firstChild ){
                        trailRouteidStr = trailRouteid[0].firstChild.nodeValue;
                        polylineInfoWindowHtml += '<p><a href="http://maps.wncoutdoors.info/gpx.php?' +
                                                'tracks=1&trackId=' + trailRouteidStr +
                                                '&output=file">Download as GPX...</a></p>';
                      }
                    }
                    
                    polylineInfoWindowHtml += '</div>';
                    
                  }
                } else if ( hikeRideHikerideid.length) {
                  hikeRideHikerideidStr = "";
                  if( hikeRideHikerideid[0].firstChild ) {
                    polylineIsHikeRide = true;
                    hikeRideHikerideidStr = hikeRideHikerideid[0].firstChild.nodeValue;
                  }
                } else {
                  // No associated trail or route - just display the name associated with the route.
                  polylineInfoWindowHtml += '<h2>' + trkNameStr + '</h2></div>';
                }
                
                // Create polylines using encoded string
                gPolylineElements = trkseg[trksegPosition].getElementsByTagName("polylineEnc");
                gPolylineLevelsElements = trkseg[trksegPosition].getElementsByTagName("polylineLevels");
                if( gPolylineElements.length ){
                  // If we found the polyline already encoded
                  if( gPolylineElements[0].firstChild && gPolylineLevelsElements[0].firstChild ) {
                    // Fire-flipping-fox splits nodes longer than 4096 bytes into chunks.
                    // Concatenate all the nodes together.
                    var polylineStr = "";
                    for (var nc = 0, nlen = gPolylineElements[0].childNodes.length; nc < nlen; nc++) {
                        polylineStr += gPolylineElements[0].childNodes[nc].nodeValue;
                    }
                    polylineLevelsStr = gPolylineLevelsElements[0].firstChild.nodeValue;
                    
                    if( polylineIsHikeRide == true ){
                      boundsForTrackZoom = createHRPolyline(polylineStr, polylineLevelsStr, hikeRideHikerideidStr);
                    } else {
                      boundsForTrackZoom = createPolylineEnc(polylineStr, polylineLevelsStr, segmentID, polylineInfoWindowHtml);
                      segmentID++;
                    }
                  }
                } else {
                  // No polyline here - encode it manually
                  trkpt = trkseg[trksegPosition].getElementsByTagName("trkpt");
                  for (trkptPosition = 0; trkptPosition < trkpt.length; trkptPosition++) {
                       trkptLat = parseFloat(trkpt[trkptPosition].getAttribute("lat"));
                       trkptLon = parseFloat(trkpt[trkptPosition].getAttribute("lon"));
                       trkptLatLng = new GLatLng(trkptLat,trkptLon);
                       boundsForTrackZoom.extend(trkptLatLng);
                       segPoints.push(new GPoint(trkptLon,trkptLat));
                  }
                  segmentPolylines[segmentID] = new GPolyline(segPoints, tcolor, twidth, topacity);
                  map.addOverlay(segmentPolylines[segmentID]);
                  segmentID++;
                }
                // Saved up the bounding box for this track
                // Get the SW, NE corners
                // Extend the main bounding box if these are outside of it
                var southWest = boundsForTrackZoom.getSouthWest();
                var northEast = boundsForTrackZoom.getNorthEast();
                boundsForZoomLevel.extend(southWest);
                boundsForZoomLevel.extend(northEast);
                
                // Add data to the feature table
                featureTableHtml += '<tbody>' +
                  '<tr><td>';
                if(typeof(trailHikecommentsStr) != 'undefined' && trailHikecommentsStr != ''){
                  featureTableHtml += '<a href="javascript:$(\'row' + segmentID + '\').toggle();">';
                }
                if(typeof(trailNameStr) != 'undefined' && trailNameStr != ''){
                  featureTableHtml += trailNameStr;
                }
                if(typeof(trailHikecommentsStr) != 'undefined' && trailHikecommentsStr != ''){
                  featureTableHtml += '</a>';
                }
                featureTableHtml += '</td><td>';
                if(typeof(trailLengthStr) != 'undefined' && trailLengthStr != ''){
                  featureTableHtml += trailLengthStr;
                }
                featureTableHtml += '</td><td>';
                if(typeof(trailDifficultyStr) != 'undefined' && trailDifficultyStr != ''){
                  featureTableHtml += trailDifficultyStr;
                }
                featureTableHtml += '</td><td>';
                if(typeof(trailSteepnessStr) != 'undefined' && trailSteepnessStr != ''){
                  featureTableHtml += trailSteepnessStr;
                }
                featureTableHtml += '</td><td>';
                if(typeof(trailTreadconditionStr) != 'undefined' && trailTreadconditionStr != ''){
                  featureTableHtml += trailTreadconditionStr;
                }
                featureTableHtml += '</td><td>';
                if(typeof(trailBlazecolorStr) != 'undefined' && trailBlazecolorStr != ''){
                  featureTableHtml += trailBlazecolorStr;
                }
                featureTableHtml += '</td><td>';
                if(typeof(trailBikeStr) != 'undefined' && trailBikeStr != ''){
                  featureTableHtml += (trailBikeStr == 1 ? 'Yes' : 'No');
                }
                featureTableHtml += '</td><td>';
                if(typeof(trailHorseStr) != 'undefined' && trailHorseStr != ''){
                  featureTableHtml += (trailHorseStr == 1 ? 'Yes' : 'No');
                }
                featureTableHtml += '</td><td>';
                if(typeof(trailAccessibleStr) != 'undefined' && trailAccessibleStr != ''){
                  featureTableHtml += (trailAccessibleStr == 1 ? 'Yes' : 'No');
                }              
                featureTableHtml += '</td><td>';
                if(typeof(trailRouteidStr) != 'undefined' && trailRouteidStr != ''){
                  featureTableHtml += '<p><a href="http://maps.wncoutdoors.info/gpx.php?' +
                    'tracks=1&trackId=' + trailRouteidStr +
                    '&output=file" class="linkGpxFile">GPX</a></p>';
                }
                featureTableHtml += '</td></tr></tbody>';
                if(typeof(trailHikecommentsStr) != 'undefined' && trailHikecommentsStr != ''){
                  featureTableHtml += '<tbody id="row' + segmentID +
                    '" style="display:none;"><tr><td colspan="10">' +
                    trailHikecommentsStr + '</td></tr></tbody>';
                }
              }
            } // End if there were some track segments
            
            if(trkNameStr == "" && trkDescStr == ""){
              trackHTML = '<strong>Track ' + (trkPosition + 1) + '</strong><br>' + trackSegmentHTML;
            } else {
              trackHTML = '<strong>' + trkNameStr + '</strong><br>' + trkDescStr + '<br>' + trackSegmentHTML;
            }
          }

          trk = [];
          
        } // End processing tracks
      } // gpxDoc
      
      if(!wptsProcessed && !trksProcessed){
        alert("No waypoints or tracks were found.");
      } else {
        map.setCenter(boundsForZoomLevel.getCenter(),
                      map.getBoundsZoomLevel(boundsForZoomLevel),
                      G_PHYSICAL_MAP);
      }
      // Add the feature table
      $('featureTable').innerHTML = featureTableHtml;
    } // readyState
  } // function
  request.send(null);
} // End load and parse GPX file

