
 var tinyicon = null;
 var map = null;
 
 function processXml() {
    //alert("In processXml()");
    var f = document.user_options;  // This is the form we'll we working with.
    var selectBox = f.xml_file
    var url = selectBox.options[selectBox.selectedIndex].value
    //document.forms[0].select.selectedIndex = 2;
 
    buildMap(url);     
    map.centerAndZoom(centerPoint, getZoomLevel(x));
 }
 
 
 function buildMap(route_url) {
 
    if (initImap() == 0) {
       map.clearOverlays();
 
       loadXMLDoc(route_url);
    }
 
    function initImap() {
       if (GBrowserIsCompatible()) {
          if (tinyicon == null) {
             tinyicon = new GIcon();
             tinyicon.image = "http://labs.google.com/ridefinder/images/mm_20_green.png";
             tinyicon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
             tinyicon.iconSize = new GSize(12, 20);
             tinyicon.shadowSize = new GSize(22, 20);
             tinyicon.iconAnchor = new GPoint(6, 20);
             tinyicon.infoWindowAnchor = new GPoint(5, 1);
          }
 
          if (map == null) {
             //alert("Creating a new Map instance.");
             map = new GMap(document.getElementById("map"));
             map.addControl(new GSmallMapControl());
             map.addControl(new GMapTypeControl());
             map.addControl(new GScaleControl());
             map.addControl(new GOverviewMapControl ());
 
 //            map.centerAndZoom(new GPoint(-81.373973, 28.432274), 9);
             //var bccPoint = new GPoint(-80.67166, 28.16788);
             //var orlandoPoint = new GPoint(-81.373973, 28.432274);
             //map.centerAndZoom(bccPoint, 5);
             //map.centerAndZoom(orlandoPoint, 8);
 
             //var center = getCenterLatLng();
             //var html = "<span class=\"small\">Wickham Pavilion<br>(next to BCC Campus)</span>";
             //var marker = createMapMarker(new GPoint(-80.67166, 28.16788), html, "red");
             //map.addOverlay(marker);
 
             GEvent.addListener(map, 'click', function(overlay, point) {
                if (point) {
                   //alert("Clicked on point!!! " + point);
                   //map.addOverlay(new GMarker(point));
                   document.getElementById('coordinate').innerHTML=point;
                   //     document.getElementById('A1').innerHTML=xmlhttp.status
                   //     document.getElementById('A2').innerHTML=xmlhttp.statusText
                   //     document.getElementById('A3').innerHTML=xmlhttp.responseText
                   //alert("Clicked on point 1 " + point);
 
                   //document.getElementById('debug').innerHTML="Before createMarker 1 for " + point;
 
                   map.addOverlay(createMapMarker(point, "", "yellow"));
                   //alert("Clicked on point 2 " + point);
                }
             });
          }
          return 0;
       }
       else {
          alert("Sorry, your browser is not compatible with the Google Maps API.\n\n" +
                "Google Maps currently supports recent versions of Firefox/Mozilla, IE 5.5+,\n" +
                "Safari 1.2+, and sort of supports Opera. IE 5.0 is not supported.");
          return -1;
       }
    }
 
    // Creates a marker whose info window displays html text
    function createMapMarker(point, html, color) {
       //document.getElementById('debug').innerHTML="createMarker 1 for " + point;
 
       var icon = new GIcon(tinyicon);
 
       //icon.image = "http://www.google.com/mapfiles/marker.png";
       if (color == "red") {
          icon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
       }
       else if (color == "green") {
          icon.image = "http://labs.google.com/ridefinder/images/mm_20_green.png";
       }
       else if (color == "yellow") {
          icon.image = "http://labs.google.com/ridefinder/images/mm_20_yellow.png";
       }
       else if (color == "orange") {
          icon.image = "http://labs.google.com/ridefinder/images/mm_20_orange.png";
       }
       else if (color == "purple") {
          icon.image = "http://labs.google.com/ridefinder/images/mm_20_purple.png";
       }
       else if (color == "blue") {
          icon.image = "http://labs.google.com/ridefinder/images/mm_20_blue.png";
       }
       else if (color == "white") {
          icon.image = "http://labs.google.com/ridefinder/images/mm_20_white.png";
       }
       else {
          icon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
       }
 
       var marker = new GMarker(point, icon);
 
       // Show this marker's index in the info window when it is clicked
       GEvent.addListener(marker, 'click', function() {
          if (html == "") {
             map.removeOverlay(marker);
          }
          else {
             marker.openInfoWindowHtml(html);
          }
       });
 
       return marker;
    }
 
 
     // Download the data in data.xml and load it on the map. The format we
     // expect is:
     //    <rte>
     //      <name>EW-IndianHarbor-WOT</name>
     //      <rtept lat="28.151286" lon="-80.599844">
     //        <time>2005-06-22T17:55:56Z</time>
     //        <name>1302BananaRiver</name>
     //        <cmt>1302 Banana River Dr</cmt>
     //        <desc>1302 Banana River Dr</desc>
     //        <sym>Waypoint</sym>
     //      </rtept>
     //      <rtept lat="28.431330" lon="-80.788136">
     //        <name>Bre1005026</name>
     //        <cmt>Grissom Pky</cmt>
     //        <desc>Grissom Pky</desc>
     //        <sym>Waypoint</sym>
     //      </rtept>
     //      <rtept lat="28.553597" lon="-82.638057">
     //         <ele>3.352800</ele>
     //         <time>2005-09-13T15:48:55Z</time>
     //         <name>CTRL BAYPORT INN</name>
     //         <cmt>03-SEP-05 4:03:57PM</cmt>
     //         <desc>03-SEP-05 4:03:57PM</desc>
     //         <sym>Flag, Blue</sym>
     //      </rtept>
     //    </rte>
    var xmlhttp;
 
    function loadXMLDoc(url) {
       // code for Mozilla, etc.
       if (window.XMLHttpRequest) {
          xmlhttp=new XMLHttpRequest();
          xmlhttp.onreadystatechange=state_Change;
          xmlhttp.open("GET",url,true);
          xmlhttp.send(null);
       }
       // code for IE
       else if (window.ActiveXObject) {
          xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
          if (xmlhttp) {
             xmlhttp.onreadystatechange=state_Change;
             xmlhttp.open("GET",url,true);
             xmlhttp.send();
          }
       }
    }
 
    function state_Change() {
       // if xmlhttp shows "loaded"
       if (xmlhttp.readyState==4) {
          // if "OK"
          if (xmlhttp.status==200) {
             //alert("XML data OK");
             var xmlDoc = xmlhttp.responseXML;
             //alert("Starting on route points...");
             var rteElems = xmlDoc.documentElement.getElementsByTagName("rte");
             var nRtePts = plotRoute(rteElems);
 
             //alert("Starting on track elements...");
             var trkElems = xmlDoc.documentElement.getElementsByTagName("trk");
             plotTracks(trkElems, nRtePts);
 
 //     document.getElementById('A1').innerHTML=xmlhttp.status
 //     document.getElementById('A2').innerHTML=xmlhttp.statusText
 //     document.getElementById('A3').innerHTML=xmlhttp.responseText
          }
          else {
             alert("Problem retrieving XML data:" + xmlhttp.statusText);
          }
       }
    }
 
    function plotRoute(rteElems) {
       //alert("Route points count = " + rteElems.length);
 
       if (rteElems.length > 0) {
          var rtName, name;
          var maxLon = -1000;
          var minLon =  1000;
          var maxLat = -1000;
          var minLat =  1000;
          var lon, lat;
 //         var markers = new Array();
          var markerIdx = 0;
          var markers   = new Array(500); // TJ: debug
          var rtGPointArray = new Array();
 
          for (var i=0; i<rteElems.length; i++) {
             rtName = rteElems[i].getElementsByTagName("name")[0].childNodes[0].nodeValue + '<br>';
 
             var rtePtElems = rteElems[i].getElementsByTagName("rtept");
 
             if (rtePtElems.length > 0) {
                //alert("Processing route " + name + " with " + rtePtElems.length + " points.");
 
                //alert("rtePtElems count = " + rtePtElems.length);
                var gPoints = new Array(rtePtElems.length);
                var name, cmt, html, color;
                //var prevName  = null;
                //var prevPoint = null;
 
                for (var j=0; j<rtePtElems.length; j++) {
                   lon = parseFloat(rtePtElems[j].getAttribute("lon"));
                   lat = parseFloat(rtePtElems[j].getAttribute("lat"));
 
                   maxLon = Math.max(maxLon, lon);
                   minLon = Math.min(minLon, lon);
                   maxLat = Math.max(maxLat, lat);
                   minLat = Math.min(minLat, lat);
 
                   gPoints[j]  = new GPoint(lon, lat);
 
                   var point = new GPoint(lon, lat);
                   //var marker = createMapMarker(gPoints[j], "rtept", "orange");
                   name = rtePtElems[j].getElementsByTagName("name")[0].childNodes[0].nodeValue;
 
                   // Add a marker if the first char is not a \ (must be a .anr to .gpx conversion)
                   // and not number.
                   var re = /^[-]?\d*\.?\d*$/; // RegEx for a number
                   if (name.indexOf('\\') != 0 &&
                       ! name.match(re)) {
 
                      var cmtArray = rtePtElems[j].getElementsByTagName("cmt");
                      if (cmtArray.length > 0) {
                         cmt  = cmtArray[0].childNodes[0].nodeValue;
                         if (cmt != name) {
                            html = '<span class="small">' + rtName + name + '<br>' + cmt + '</span>';
                         }
                         else {
                            html = '<span class="small">' + rtName + name + '</span>';
                         }
                      }
                      else {
                         html = '<span class="small">' + rtName + name + '</span>';
                      }
 
                      if (html.indexOf('CTRL') != -1) {
                         color = "red";
                      }
                      else if (rtName != "") {
                         color = "blue";
                      }
                      else if (j == 0) {
                         color = "green";
                      }
                      else {
                         color = "white";
                      }
 
                      rtName = "";

                      // Add the marker
                      if (markers[point] == null) { // Point must be unique
                         var mkr = createMapMarker(point, html, color);
                         markers.length;
                         if (markerIdx < markers.length) {
                            markers[markerIdx] = mkr;
                            markerIdx++;
                         }
                         else {
                            markers[markers.length] = mkr;
                         }
 
                         //alert("Adding marker '" + name + "' typeof '" + (typeof name) + "'");
                         markers[point] = mkr;
                      }
                   }
 
                   // Debug code...
                   //if (prevPoint != null) {
                   //   var d = gcd(prevPoint.x, prevPoint.y, point.x, point.y);
                   //   if (d > 50) {
                   //      alert("Distance from '" + prevName + "' to '" + name + " is " + d + " miles.");
                   //   }
                   //}
                   //prevPoint = point;
                   //prevName  = name;
                }
 
                rtGPointArray[rtGPointArray.length] = gPoints;
             }
          }
 
          zoomAndCenter(maxLon, minLon, maxLat, minLat);
 
          for (var m=0; m<rtGPointArray.length; m++) {
             //alert("Plotting polyline " + (m+1) + " of " + rtGPointArray.length);
             plotPolyline(rtGPointArray[m], "#ff0000", 3, 0.4, 200);
          }
 
          //for (var k=0; k<markers.length; k++) {
          for (var k=markers.length - 1; k>=0; k--) {
             //if (k % 200 == 0) {
             //   alert("Overlayed " + k + " of " + markers.length + " markers.");
             //}
             if (markers[k] != null) {
                map.addOverlay(markers[k]);
             }
          }
          //alert("Finished overlaying "+ markers.length + " markers.");
       }
       return rteElems.length;
    }
 
 
    function plotTracks(trkElems, nRtePts) {
       if (trkElems.length > 0) {
          var name;
          var maxLon = -1000;
          var minLon =  1000;
          var maxLat = -1000;
          var minLat =  1000;
          var lon, lat;
 
          for (var i=0; i<trkElems.length; i++) {
             name = trkElems[i].getElementsByTagName("name")[0].childNodes[0].nodeValue;
 
             //alert("Processing track " + i + ", " + name);
             var trkPointElems = trkElems[i].getElementsByTagName("trkpt");
 
             // Add the trail head marker
             lon = parseFloat(trkPointElems[0].getAttribute("lon"));
             lat = parseFloat(trkPointElems[0].getAttribute("lat"));
             var html = '<span class="small">Trail Start<br>' + name + '</span>';
             var trlHeadMarker = createMapMarker(new GPoint(lon, lat), html, "purple");
 
             var gPoints = new Array(trkPointElems.length);
             var maxSize = 200;
 
             for (var j=0; j<trkPointElems.length; j++) {
                lon = parseFloat(trkPointElems[j].getAttribute("lon"));
                lat = parseFloat(trkPointElems[j].getAttribute("lat"));
 
                maxLon = Math.max(maxLon, lon);
                minLon = Math.min(minLon, lon);
                maxLat = Math.max(maxLat, lat);
                minLat = Math.min(minLat, lat);
 
                gPoints[j]  = new GPoint(lon, lat);
                //gPointsAA[j/maxSize][j % maxSize]  = new GPoint(lon, lat);
             }
 
             if (nRtePts == 0) {
                zoomAndCenter(maxLon, minLon, maxLat, minLat);
             }
 
             map.addOverlay(trlHeadMarker);
 
             //alert("  Making polyline...");
             plotPolyline(gPoints, "#ff00ff", 3, 0.4, 200);
          }
       }
    }
 
     // Plot a polyline in segments to avoid a bug in Mozilla
     function plotPolyline(gPoints, colorHex, weight, tranparency, chunkSize) {
        var size1    = gPoints.length / chunkSize; // 2682 / 100 = 26
        var lastSize = gPoints.length % chunkSize; // 2682 % 100 = 82
 
        // Array to repeatedly fill with points for each polyline segment.
        // Make it one bigger than the chunkSize to fill-in the gap between segments.
        var array = new Array(chunkSize + 1);
        var idx = 0;
        var polyline;
 
        for (var i=0; i < (size1 - 1); i++) {
           var jLast;
           for (var j=0; j<chunkSize; j++) {
              array[j] = gPoints[idx];
 
              idx = idx + 1;
              jLast = j;
           }
 
           if (lastSize > 0) {
              // Manually add duplicate of first point in the next section to
              // avoid a gap between polylines.
              array[jLast+1] = gPoints[idx];
           }
 
           polyline = new GPolyline(array, colorHex, weight, tranparency);
           //alert("  Overlaying polyline (" + i + ")...");
           map.addOverlay(polyline);
        }
 
        // Plot the last chuck
        array = new Array(lastSize);
        for (var j=0; j<lastSize; j++) {
           array[j] = gPoints[idx];
 
           idx = idx + 1;
        }
        polyline = new GPolyline(array, colorHex, weight, tranparency);
        //alert("  Overlaying polyline (" + gPoints.length + " points)...");
        map.addOverlay(polyline);
     }
 
     function avg(a, b) {
        return (a + b) / 2;
     }
 
     // Compute the great-circle distance between 2 geo-points (miles)
     function gcd(lon1, lat1, lon2, lat2) {
        //       dlon = lon2 - lon1
        //       dlat = lat2 - lat1
        //       a = (sin(dlat/2))^2 + cos(lat1) * cos(lat2) * (sin(dlon/2))^2
        //       c = 2 * arcsin(min(1,sqrt(a)))
        //       distance = (Earth Radius) * c
        var degToRadians = 3.141592658 / 180;
 
        var dlon = (lon2 - lon1) * degToRadians;
        var dlat = (lat2 - lat1) * degToRadians;
        var a = Math.pow((Math.sin(dlat/2)), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow((Math.sin(dlon/2)), 2);
        //var c = 2 * Math.atan2( Math.sqrt(a), Math.sqrt(1-a) );
        var c = 2 * Math.asin(Math.min(1, Math.sqrt(a)));
        var d = 3964 * c;  // miles
 
        //alert("distance = " + d + " miles, between (" + lon1 + "," + lat1 + ") and (" +
        //      lon2 + "," + lat2 + ")");
        return d;
     }
 
     function getZoomLevel(distance) {
        var max = 3000;
        if (distance > max) {
           return 13;
        }
        else if (distance > (max/2)) {
           return 12;
        }
        else if (distance > (max/4)) {
           return 11;
        }
        else if (distance > (max/8)) {
           return 10;
        }
        else if (distance > (max/16)) { // 187
           return 9;
        }
        else if (distance > (max/32)) { // 94
           return 8;
        }
        else if (distance > (max/64)) { // 47
           return 7;
        }
        else if (distance > (max/128)) { // 24
           return 6;
        }
        else if (distance > (max/256)) { // 12
           return 5;
        }
        else if (distance > (max/512)) { // 6
           return 4;
        }
        else {
           return 3;
        }
     }      var centerPoint;     var x;
 
     function zoomAndCenter(maxLon, minLon, maxLat, minLat) {
        var spanLon = Math.abs(maxLon - minLon);
        var spanLat = Math.abs(maxLat - minLat);
        //alert("maxLon=" + maxLon + ",minLon=" + minLon +
        //      ",maxLat=" + maxLat + ",minLat=" + minLat +
        //      ",spanLon=" + spanLon + ",spanLat=" + spanLat);
 
        centerPoint = new GPoint(avg(maxLon, minLon),
                                     avg(maxLat, minLat));
 
        x = gcd(maxLon, minLat, minLon, maxLat);
        map.centerAndZoom(centerPoint, getZoomLevel(x));
     }
 }
 
