﻿// COOKIE FUNCTIONS

function cookieSet( name, value, expires, path, domain, secure ) 
{
    // set time, it's in milliseconds
    var today = new Date();
    today.setTime( today.getTime() );

    /*
    if the expires variable is set, make the correct 
    expires time, the current script below will set 
    it for x number of days, to make it for hours, 
    delete * 24, for minutes, delete * 60 * 24
    */
    if ( expires )
    {
        expires = expires * 1000 * 60 * 60 * 24;
    }
    var expires_date = new Date( today.getTime() + (expires) );

    document.cookie = name + "=" +escape( value ) +
    ( ( expires ) ? ";expires=" + expires_date.toGMTString() : "" ) + 
    ( ( path ) ? ";path=" + path : "" ) + 
    ( ( domain ) ? ";domain=" + domain : "" ) +
    ( ( secure ) ? ";secure" : "" );
}

function cookieGet( check_name ) {
	// first we'll split this cookie up into name/value pairs
	// note: document.cookie only returns name=value, not the other components
	var a_all_cookies = document.cookie.split( ';' );
	var a_temp_cookie = '';
	var cookie_name = '';
	var cookie_value = '';
	var b_cookie_found = false; // set boolean t/f default f
	
	for ( i = 0; i < a_all_cookies.length; i++ )
	{
		// now we'll split apart each name=value pair
		a_temp_cookie = a_all_cookies[i].split( '=' );
		
		
		// and trim left/right whitespace while we're at it
		cookie_name = a_temp_cookie[0].replace(/^\s+|\s+$/g, '');
	
		// if the extracted name matches passed check_name
		if ( cookie_name == check_name )
		{
			b_cookie_found = true;
			// we need to handle case where cookie has no value but exists (no = sign, that is):
			if ( a_temp_cookie.length > 1 )
			{
				cookie_value = unescape( a_temp_cookie[1].replace(/^\s+|\s+$/g, '') );
			}
			// note that in cases where cookie is initialized but no value, null is returned
			return cookie_value;
			break;
		}
		a_temp_cookie = null;
		cookie_name = '';
	}
	if ( !b_cookie_found )
	{
		return null;
	}
}				

function urlescape(url)
{
   var escaped = escape(url);
   escaped = escaped.replace(/\+/g, '%2B');
   return escaped;

}

// Track functions

function saveTrack(trackId, address) {

    var url = "/ws/track/update";

    var putXml = "<trackHeader>";
    putXml += "<trackHeaderId>" + trackId + "</trackHeaderId>";
    putXml += "<address><![CDATA[" + address + "]]></address>";
    putXml += "</trackHeader>";

    //GLog.write("track xml: " + putXml);
    dojo.rawXhrPut({
        url: url,
        handleAs: "xml",
        timeout: 20000,              // Time in milliseconds
        contentType: "text/xml",
        putData: putXml,
        load: onTrackSaveSuccess,
        error: onTrackSaveFailure
    });
}

function onTrackSaveSuccess(response, ioargs) {
    //GLog.write("on track success called: " + response.textContent);
}

function onTrackSaveFailure(response, ioargs) {
    //GLog.write("on track success called: " + response.textContent);
}


// SEGMENT UI FUNCTIONS

function saveSegment(segmentId, name, reviewFlag)
{
    var putXml = "<segment><segmentId>" + segmentId + "</segmentId>";
    
    if (name != null)
      putXml += "<name>" + name + "</name>";
      
    if (reviewFlag != null)
      putXml += "<reviewFlag>" + reviewFlag + "</reviewFlag>";
      
    putXml += "</segment>";
    
    var url = "/ws/segment/" + segmentId;

    //GLog.write("segment: " + putXml);
    dojo.rawXhrPut( {  
    url: url, 
    handleAs: "xml",
    timeout: 20000,              // Time in milliseconds
    contentType: "text/xml",
    putData: putXml,
    load: onSegmentSaveSuccess,
    error: onSegmentSaveFailure
    });
}

function onSegmentSaveSuccess(response, ioargs)
{
    //GLog.write("on success called: " + response.textContent);
    var segmentName = segmentGetName(response);
    var segmentId = segmentGetId(response);
    //alert(segmentName);
    //alert(segmentId);
        
    if (segmentName != null && segmentId != null)
      segmentPageDisplayName(segmentId, segmentName);
    else
    {
      //GLog.write("error condition");
      //dumpChildren(response); 
      var error = errorGetError(response);
      segmentPageDisplayError(error);
    }
}

function errorGetError(response)
{
   return getElementValue(response, "error");
}

function onSegmentSaveFailure(response, ioargs)
{
    //GLog.write("segment save failure: " + response);
    segmentPageDisplayError(response);
}

function segmentPageDisplayName(segmentId, segmentName)
{
    //GLog.write("segmentPageDisplayName: sid: " + segmentId + " name: " + segmentName);
    var editHtml =  '<form name="displayNameForm">' + segmentName + '&nbsp;<input type="button" value="Edit" onClick="segmentPageEditName(' + segmentId + ',\'' + segmentName + '\');"></form>';
    //GLog.write("edit html: " + editHtml);
    $("nameDiv").innerHTML = editHtml;
    segmentPageDisplayError("");
}

function segmentPageDisplayError(text)
{
    $("errorDiv").innerHTML = '<font color="red">' + text + '</font>';
}

function segmentPageEditName(segmentId, segmentName)
{
    var html = '<form name="editNameForm"><input type="text" id="nameEditBox" size="30" value="' + segmentName + '">&nbsp;<input type="button" value="Save" onClick="segmentPageSubmitChange(' + segmentId + ')"><input type="button" value="Cancel" onClick="segmentPageDisplayName(' + segmentId + ',\'' + segmentName + '\');"></form>';
    $("nameDiv").innerHTML = html;
}

function segmentPageSubmitChange(segmentId)
{
    var segmentName = $("nameEditBox").value;
    saveSegment(segmentId, segmentName, null);
}

// SEGMENT DATA FUNCTIONS

function segmentGetId(segmentXml)
{
    return getElementValue(segmentXml, "segmentId");
}

function segmentGetName(segmentXml)
{
    return getElementValue(segmentXml, "name");
}

function segmentGetChars(segmentXml) {
    return getElementValue(segmentXml, "chars");
}

function segmentGetEncodedPoints(segmentXml) {
    return getElementValue(segmentXml, "encodedPoints");
}

function segmentGetEncodedLevels(segmentXml) {
    return getElementValue(segmentXml, "encodedLevels");
}

function segmentGetTotalAscent(segmentXml)
{
    return getElementValue(segmentXml, "totalAscent");
}

function segmentGetTotalDescent(segmentXml)
{
    return getElementValue(segmentXml, "totalDescent");
}

function segmentGetTotalDistance(segmentXml)
{
    return getElementValue(segmentXml, "totalDistance");
}

function segmentGetMedianLatitude(segmentXml)
{
    return getElementValue(segmentXml, "medianLatitude");
}

function segmentGetMedianLongitude(segmentXml)
{
    return getElementValue(segmentXml, "medianLongitude");
}

function createLocationFromXml(locationNode)
{
    var latitude = getElementValue(locationNode, "latitude");
    var longitude = getElementValue(locationNode, "longitude");

    return locationCreateLocation(latitude, longitude);
}

function segmentGetStartLocation(segmentXml)
{
    var startLocationNode = getSubelement(segmentXml, 'startLocation');
    return createLocationFromXml(startLocationNode);
}

function segmentGetEndLocation(segmentXml)
{
    var endLocationNode = getSubelement(segmentXml, 'endLocation');
    return createLocationFromXml(endLocationNode);
}

// ROUTE UI FUNCTIONS

function loadRoute(twMap)
{
    var url = "/ws/route/" + twMap["routeName"];
    //GLog.write("loadRoute ws url: " + url + "\n");

    delete twMap["routeXml"];
    
    dojo.xhrGet( {  
        url: url, 
        handleAs: "xml",
        timeout: 300000,              // Time in milliseconds
        load: onRouteLoadSuccess,
        error: onRouteLoadFailure
    });
    
   
}

function onRouteLoadSuccess(response, ioargs)
{
    //GLog.write("onRouteLoadSuccess called: " + response);
    //GLog.write(response);
    var twMap = twMaps[0];
    twMap["routeXml"] = response;    
    
    //routePageDisplayGDirections(twMap);
    //mapDisplayWaypoints(twMap);
    routePageMarkClean();
    routePageDisplayRoute(twMap);

    //GLog.write("route ID: " + routeGetRouteId(twMap));
    
    //var firstRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], 0, -1, true);
    //if (firstRouteMapping == null)
    //  routePageDisplayInstructions();

    GEvent.addListener(twMap["mapControl"], 'click', routePageMapClicked);
    GEvent.addListener(twMap["mapControl"], 'singlerightclick', routePageMapRightClicked);
}

function onRouteLoadFailure(response, ioargs)
{
    // TODO:  can we trap for not authorized here to advise the user that they need to log in first?
    //GLog.write("load of route failed" + response);
}
 
function saveRoute(twMap)
{
    //GLog.write("routeName: " + twMap["routeName"]);
    var url = "/ws/route/" + twMap["routeName"];
    //GLog.write("saving route to " + url);
       
    var xml = "";
    if (twMap["routeXml"].xml != null)
      xml = twMap["routeXml"].xml;
    else
      xml = new XMLSerializer().serializeToString(twMap["routeXml"]);
     
    dojo.rawXhrPut( {  
        url: url, 
        handleAs: "xml",
        timeout: 100000,              // Time in milliseconds
        contentType: "text/xml",
        putData: xml,
        load: onRouteSaveSuccess,
        error: onRouteSaveFailure
        });
}
 
function onRouteSaveSuccess(response, ioargs)
{
    //GLog.write("onRouteSaveSuccess called\n");
    //GLog.write(response);

    routePageMarkClean();
    
    var twMap = twMaps[0];
    twMap["routeXml"] = response;
    twMap["dirtyRoute"] = 0;
    routePageDisplayRoute(twMap);

    alert("Your route has been successfully saved.");
}

function onRouteSaveFailure(response, ioargs)
{
    //GLog.write("save of route failed: " + response);
    alert("A problem occurred while trying to save your route, please try again.");
}

var routeXmlCallback = null;
function loadRouteXml(routeName, callback)
{
    var url = "/ws/route/" + routeName;
    //GLog.write("loadRouteXml ws url: " + url + "\n");

    dojo.xhrGet( {  
        url: url, 
        handleAs: "text",
        timeout: 20000,              // Time in milliseconds
        load: onRouteXmlLoadSuccess,
        error: onRouteXmlLoadFailure
    });
    
    routeXmlCallback = callback;
}

function onRouteXmlLoadSuccess(response, ioargs)
{
	//GLog.write("loadRouteXml success\n");
	routeXmlCallback(response);
}

function onRouteXmlLoadFailure(response, ioargs)
{
	//GLog.write("loadRouteXml failure\n");
	routeXmlCallback(null);
}

//bbox UI functions

function loadBBox(twMap)
{
    var bounds = twMap["mapControl"].getBounds();
    var url = "/ws/bbox/" + bounds.getSouthWest().lng() + "," + bounds.getSouthWest().lat() + "," + 
                                                bounds.getNorthEast().lng() + "," + bounds.getNorthEast().lat() + "?edges=0&clusters=0&chars=0&encodeSegments=1";

    //GLog.write("loadBBox ws url: " + url);

    dojo.xhrGet( {  
        url: url, 
        handleAs: "xml",
        timeout: 100000,              // Time in milliseconds
        load: onBBoxLoadSuccess,
        error: onBBoxLoadFailure
    });
}

function onBBoxLoadSuccess(response, ioargs)
{
    var twMap = twMaps[0];
    //twMap["bboxXml"] = response;

    shredBBoxResponse(response);
    //mapDisplaySegmentLinks(twMap);
}

function onBBoxLoadFailure(response, ioargs)
{
    //GLog.write("bbox load failed: " + response);
}

function SegmentObject()
{
    this.segment_id         = null;
    this.encodedPoints      = null;
    this.encodedLevels      = null;
    this.startLocation      = null;
    this.endLocation = null;
    this.distance = 0;
    this.chars              = null;

    this.polyline           = null;
    this.inRoute            = 0;
    this.drawn              = 0;
    this.color = 0;
    this.startMarker        = null;
    this.endMarker = null;
}

SegmentObject.prototype.loadFromXml = function loadFromXml(segmentXml) {
    this.segment_id = segmentGetId(segmentXml);
    this.encodedPoints = segmentGetEncodedPoints(segmentXml);
    this.encodedLevels = segmentGetEncodedLevels(segmentXml);
    this.startLocation = segmentGetStartLocation(segmentXml);
    this.endLocation = segmentGetEndLocation(segmentXml);
    this.distance = segmentGetTotalDistance(segmentXml);

    this.chars = segmentGetChars(segmentXml);
}

function routePageDrawSegment(twMap, routeMapping) {


    //GLog.write("routePageDrawSegment");
    var segmentId = routeMappingGetMemberId(routeMapping);
    if (segmentId == undefined)
      return;

    var segment = twMap["segments"][segmentId];
    if (segment == undefined) {
        // bbox has not been loaded yet, we don't have the segment encoded polyline yet so just note that this is in the route,
        // we'll get to drawing it when we receive the bbox data.
        segment = twMap["segments"][segmentId] = new SegmentObject();
        segment.segment_id = segmentId;
        segment.inRoute = 1;
    } else {
        segment.inRoute = 1;
        mapDrawSegment(twMap, segment);
    }

    var position = routeMappingGetPosition(routeMapping);
    var forward = routeMappingGetForward(routeMapping);

    var markerLocation = locationCreateGLatLng(segment.endLocation);
    if (forward == 1) {
        markerLocation = locationCreateGLatLng(segment.endLocation);
        //GLog.write("adding segment in forward direction");
    } else {
        markerLocation = locationCreateGLatLng(segment.startLocation);
        //GLog.write("adding segment in reverse direction");
    }

    mapDrawWaypoint(twMap, position, markerLocation, true);

}

function Range(rangeXml) {
    this.range_id = rangeGetId(rangeXml);
    this.encodedPoints = rangeGetEncodedPoints(rangeXml);
    this.encodedLevels = rangeGetEncodedLevels(rangeXml);
    var endLocation = rangeGetEndLocation(rangeXml);
    this.endLocation = new GLatLng(endLocation["latitude"], endLocation["longitude"]);
    var startLocation = rangeGetStartLocation(rangeXml);
    this.startLocation = new GLatLng(startLocation["latitude"], startLocation["longitude"]);

    this.polyline = null;
    this.drawn = 0;
    this.startMarker = null;
    this.endMarker = null;
}

function routePageDrawTrack(twMap, routeMapping) {
    //GLog.write("routePageDrawTrack");
    var rangeXml = routeMappingGetRange(routeMapping);
    var rangeId = rangeGetId(rangeXml);

    var range = twMap["ranges"][rangeId];
    if (range == undefined) {
        range = twMap["ranges"][rangeId] = new Range(rangeXml);
    }

    if (range.drawn == 0) {
        mapDrawTrack(twMap, range, routeMapping);
    }
    
}

function mapDrawTrack(twMap, range, routeMapping) {
    //GLog.write("displaying range id: " + range.range_id);
    if (range.polyline != null) {
        twMap["mapControl"].removeOverlay(range.polyline);
        range.polyline = null;
        range.drawn = 0;
    }

    var position = routeMappingGetPosition(routeMapping);
    var forward = routeMappingGetForward(routeMapping);

    //GLog.write("building polyline for range id: " + range.range_id);

    range.polyline = GPolyline.fromEncoded({
        color: "#5555ff",
        weight: 4,
        opacity: 0.7,
        points: range.encodedPoints,
        levels: range.encodedLevels,
        numLevels: 12,
        zoomFactor: 2
    });

    //GEvent.addListener(segment.polyline, 'click', function() { routePageAddSegment(segment.segment_id); });
    //GEvent.addListener(segment.polyline, 'mouseover', function() { routePageHighlightRange(twMap, range); });
    //GEvent.addListener(segment.polyline, 'mouseout', function() { routePageUnhighlightRange(twMap, range); });

    //GLog.write("adding polyline for range id: " + range.range_id);
    twMap["mapControl"].addOverlay(range.polyline);

    // draw termination waypoint

    var waypointLocation;
    if (forward == 1)
        waypointLocation = range.endLocation;
    else
        waypointLocation = range.startLocation;

    mapDrawWaypoint(twMap, position, waypointLocation, false);
    //GLog.write("adding waypoint mapControl: " + twMap["mapControl"] + " to position: " + position);
    
    range.drawn = 1;
    //GLog.write("done");
}

function mapDrawWaypoint(twMap, position, markerLocation, canDrag) {

    var markerIcon = new GIcon();
    markerIcon.image = "/ui/dd-start.png";
    markerIcon.iconSize = new GSize(32, 32);
    markerIcon.iconAnchor = new GPoint(16, 32);

    //GLog.write("in mapDrawWaypoint");
    if (twMap["waypoints"][position] != undefined) {
        twMap["mapControl"].removeOverlay(twMap["waypoints"][position]);
        twMap["waypoints"][position] = null;
    }

    //GLog.write("creating gmarker: " + position);

    twMap["waypoints"][position] = new GMarker(markerLocation, { icon: markerIcon, draggable: canDrag });
    if (canDrag)
      waypointSetDragEndEvent(twMap, position);

    //GLog.write("displaying gmarker: " + position);

    twMap["mapControl"].addOverlay(twMap["waypoints"][position]);
}

function routePageDrawWaypoint(twMap, routeMapping) {
    // GLog.write("in routePageDrawWaypoint");
    var position = routeMappingGetPosition(routeMapping);        
    var waypoint = routeMappingGetWaypoint(routeMapping);
    //GLog.write("waypoint: " + waypoint);
    //GLog.write("position: " + position);
    var latitude = waypointGetLatitude(waypoint);
    var longitude = waypointGetLongitude(waypoint);
    //GLog.write("latitude: " + latitude + " longitude:" + longitude);

    var markerLocation = new GLatLng(latitude, longitude);
    mapDrawWaypoint(twMap, position, markerLocation, true);

    //GLog.write("adding waypoint mapControl: " + twMap["mapControl"] + " to position: " + position);
}

function shredBBoxResponse(response) {

    //GLog.write("shredBBoxResponse");
    var twMap = twMaps[0];
    var segments = response.getElementsByTagName('segment');
    var inRoute = null;
    for (idx = 0; idx < segments.length; idx++) {
       var segmentXml = segments[idx];
       var segmentId = segmentGetId(segmentXml);
       var segment = twMap["segments"][segmentId];
       if (segment == undefined) {
            segment = twMap["segments"][segmentId] = new SegmentObject();
       }
       segment.loadFromXml(segmentXml);
       if (segment.inRoute == 0)
         mapDrawSegment(twMap, segment);
    }

    routePageDisplayRoute(twMap);
    //GLog.write("shredDone");
}

var mapColorsForCharId = ["#5555ff", "#FF0000", "#FF9800", "#66FF33", "#0C998FF", "#3399FF", "#00FFFF", "#FB0AE1", "#CC72BD", "#996600"];

function mapColorForSegment(twMap, segment) {

    //GLog.write("segment inroute: " + segment.inRoute);
    if (segment == undefined || segment.chars == undefined || segment.inRoute) {
      //  GLog.write("returning highlighted color.");
        return mapColorsForCharId[0];
    }
        
    var charIds = segment.chars.split(",");
    var idx;
    for (idx = 0; idx < charIds.length; idx++) {
        if ($(twMap["div"] + "category" + charIds[idx]).checked) {
            return mapColorsForCharId[charIds[idx]];
        }
    }

    return null;
}

function mapDrawSegment(twMap, segment) {
//    GLog.write("displaying segment id: " + segment.segment_id);

    var color = mapColorForSegment(twMap, segment);
 //   GLog.write("seg color:  " + segment.color + " color: " + color);
   // GLog.write("drawn:  " + segment.drawn);
    
    if (segment.color == color && segment.drawn == 1) {
        //GLog.write("no drawing required on segment, returning.");
        return;  // NOP
    }  

    segment.color = color;


    //GLog.write("color: " + segment.color);

    if (segment.polyline != null)
    {
      twMap["mapControl"].removeOverlay(segment.polyline);
      segment.polyline = null;
      segment.drawn = 0;
    }

    //GLog.write("building polyline for segment id: " + segment.segment_id);

    if (segment.color == null)
    {
      //GLog.write("segment.color is null, done");
      return;
    }

    // error encoding of points it seems?	
    if (segment.encodedPoints == "??")
      return;
            
 //   GLog.write("id: "+ segment.segment_id + " segcolor: " + segment.color + " points: " + segment.encodedPoints + " levels: "+ segment.encodedLevels);

    segment.polyline = GPolyline.fromEncoded({   
                            color: segment.color,   
                            weight: 4,   
                            opacity: 0.7,   
                            points: segment.encodedPoints,
                            levels: segment.encodedLevels,
                            numLevels: 12,
                            zoomFactor: 2
                        });
   
    GEvent.addListener(segment.polyline, 'click',       function() { routePageAddSegment(segment.segment_id); });
   // GEvent.addListener(segment.polyline, 'mouseover',   function() { routePageHighlightSegment(twMap, segment); });
   // GEvent.addListener(segment.polyline, 'mouseout',    function() { routePageUnhighlightSegment(twMap, segment); });
    
    //GLog.write("adding polyline for segment id: " + segment.segment_id);
    twMap["mapControl"].addOverlay(segment.polyline);
    segment.drawn = 1;
    //GLog.write("done");
}

function mapUndrawSegments(twMap) {
    var segment = null;
    for (segmentId in twMap["segments"]) {
        var segment = twMap["segments"][segmentId];
        //GLog.write("undrawing segment id: " + segment.segment_id);
        if (segment.polyline != null) {
            twMap["mapControl"].removeOverlay(segment.polyline);
            segment.polyline = null;
        } 
    }
}

//routePage UI functions

function routePageDisplayInstructions() {

    var twMap = twMaps[0];
    var center = twMap["mapControl"].getCenter();
    var bounds = twMap["mapControl"].getBounds();
    var latitude = (center.lat() + 4*bounds.getSouthWest().lat()) / 5;
    var display = new GLatLng(latitude, center.lng());
    twMap["mapControl"].openInfoWindowHtml(display, "<div style='width:400px;height:275px;'><h3>Route Editing Help:</h3><p/><b>Clicking on the map</b> adds a waypoint at that point.<p/><b>Right Clicking (Mac: Control-Click) on a waypoint</b> deletes an existing waypoint.<p/><b>Clicking on the blue route between waypoints</b> inserts a waypoint in the route between the two that it connects.<p/><b>Save</b> sends your route changes to Trailguru.<p/><b>Revert</b> reloads the last version saved.<p/><b>Clone</b> uses this route as a template to create a new route. <p/><b>Entering a location and pressing Waypoint</b> centers the map on that location and adds a waypoint. </div>");

}

function routePageEditPermsChanged() {
    var editPerms = $("editPerms").value;
    //GLog.write("editPerms: " + editPerms);
    routeSetEditPerms(editPerms);
    routePageMarkDirty();
}

function routePageCloneRoute() {
    if (routeGetRouteId(twMaps[0]) != null)
      window.location.href='/ui/routes/createRoute.php?rid=' + routeGetRouteId(twMaps[0]);
}

function routePageMapRightClicked(point, src, overlay) {
    //GLog.write("got right click");
    if (overlay instanceof GMarker) {
        //GLog.write("is marker");

        var twMap = twMaps[0];
        var currentPosition = 0;
        var first = true;
        for (currentRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], 0, -1, true);
             currentRouteMapping != null;
             currentRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], currentPosition, 1, false)) {
            currentPosition = routeMappingGetPosition(currentRouteMapping);
            if (twMap["waypoints"][currentPosition] == overlay || first && overlay == twMap["waypoints"][-1]) {
                routePageRemove(twMaps[0], currentPosition);
                routePageMarkDirty();
                routePageDisplayRoute(twMap);
                return;
            }
            first = false;
        }
    } else
    if (overlay instanceof GPolyline) {
      //GLog.write("is a polyline");
      var intersectingRouteMapping = routePageMatchOverlay(twMap, overlay);
      if (intersectingRouteMapping != null) {
          //GLog.write("removing route to next");
          var position = routeMappingGetPosition(intersectingRouteMapping);
          twMap["mapControl"].removeOverlay(twMap["polyline"][position]);
          twMap["polyline"][position] = null;
          routeMappingDeleteRoutePoints(intersectingRouteMapping);
      }

    }
}

function routePageMapClicked(overlay, latlng, overlaylatlng) {
    var twMap = twMaps[0];

    //GLog.write("overlay: " + overlay);
    //GLog.write("latlng: " + latlng);
    //GLog.write("overlaylatlng: " + overlaylatlng);
    if (overlaylatlng != null) {
        var intersectingRouteMapping = routePageMatchOverlay(twMap, overlay);
        if (intersectingRouteMapping == null) {
            //GLog.write("didn't find intersection route mapping");
            return;
        }
        //GLog.write("found route mapping");
        routePageInsertWaypointAfter(twMap, overlaylatlng.lat(), overlaylatlng.lng(), intersectingRouteMapping);
        //GLog.write("insert waypoint after");
        routePageMarkDirty();
    } else if (latlng != null) {
      //GLog.write("routePagMapClicked adding waypoint");
      routePageAddWaypoint(twMap, latlng.lat(), latlng.lng());
    }

}

function routePageInsertWaypointAfter(twMap, latitude, longitude, insertAfterRouteMapping) {

    var lastRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], 0, 1, true);

    //GLog.write("routePageInsertWaypointAfter: before add waypoint.");

    var addedRouteMapping = routeAddWaypoint(twMap["routeXml"], latitude, longitude);

    //GLog.write("routePageInsertWaypointAfter: after add waypoint.");

    //routePageCreateWaypoint(twMap, addedRouteMapping);
   // GLog.write("added starting position: " + routeMappingGetPosition(addedRouteMapping));
    //GLog.write("inserting after position: " + routeMappingGetPosition(insertAfterRouteMapping));

    var currentPosition = 0;

    for (currentRouteMapping = lastRouteMapping;
         currentRouteMapping != insertAfterRouteMapping;
         currentRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], currentPosition, -1, false)) {

       //GLog.write("swapping position with current: " + routeMappingGetPosition(currentRouteMapping) + " addedRouteMapping now at: " + routeMappingGetPosition(addedRouteMapping));
       routeMappingSwapPosition(twMap, currentRouteMapping, addedRouteMapping);
       //GLog.write("swap position done");
       currentPosition = routeMappingGetPosition(addedRouteMapping);
    }

    //GLog.write("added final position: " + routeMappingGetPosition(addedRouteMapping));

    routePageDeleteRouting(twMap, insertAfterRouteMapping);
    routePageDeleteRouting(twMap, addedRouteMapping);
    
//    var insertAfterPosition = routeMappingGetPosition(insertAfterRouteMapping);
//    if (twMap["polyline"][insertAfterPosition] != null) {
//        GLog.write("insertAfter removing overlay at " + insertAfterPosition);
//        twMap["mapControl"].removeOverlay(twMap["polyline"][insertAfterPosition]);
//        twMap["mapControl"][insertAfterPosition] = null;
//    }

    //GLog.write("routePageInsertWaypointAfter:  done, doing display route.");
    routePageMarkDirty();
    routePageDisplayRoute(twMap);
}

function routePageMatchOverlay(twMap, overlay)
{
    var currentPosition = 0;
    for (currentRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], 0, -1, true);
         currentRouteMapping != null;
         currentRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], currentPosition, 1, false))
    {
        currentPosition = routeMappingGetPosition(currentRouteMapping);
        //GLog.write("route mapping postion " + currentPosition + ": polyline: " + twMap["polyline"][currentPosition] + " overlay:" + overlay);
        if (twMap["polyline"][currentPosition] == overlay)
          return currentRouteMapping;     
    }
    
    return null;
}

function routePageAddWaypoint(twMap, latitude, longitude)
{
    // 1 -> 3 -> 6  ==> 1 -> 3 -> 6R -> 7

    var routeMapping = routeAddWaypoint(twMap["routeXml"], latitude, longitude);
    //routePageCreateWaypoint(twMap, routeMapping);
    
    // previous entry already doesn't have routePoints, so just recalc
    routePageMarkDirty();
    routePageDisplayRoute(twMap);
}

function routePageDisplayRouteOnMap(twMap)
{
    //GLog.write("routePageDisplayRouteOnMap: " + twMap["routeXml"]);
    var routeXml = twMap["routeXml"];
    if (routeXml == undefined)
      return;
        
    twMap["recomputeStatus"] = new Array();

    var directionsRecomputes = 0;
    var firstRouteMapping = routeGetAdjacentRouteMapping(routeXml, 0, -1, true);
    var currentRouteMapping = firstRouteMapping;
    for (nextRouteMapping = null;
         currentRouteMapping != null;
         currentRouteMapping = nextRouteMapping) {

        var position = routeMappingGetPosition(currentRouteMapping);
        // DISPLAY SECTION
        //GLog.write("route mapping: " + position + " : " + routeMappingGetTypeId(currentRouteMapping));

        if (routeMappingGetTypeId(currentRouteMapping) == kRouteMapping_TrackType) {
            //GLog.write("displaying route track range");
            routePageDrawTrack(twMap, currentRouteMapping);
        } else if (routeMappingGetTypeId(currentRouteMapping) == kRouteMapping_SegmentType) {
            //GLog.write("displaying route segment @ position: " + routeMappingGetPosition(currentRouteMapping));
            routePageDrawSegment(twMap, currentRouteMapping);
        } else if (routeMappingGetTypeId(currentRouteMapping) == kRouteMapping_WaypointType) {
            //GLog.write("displaying route waypoint");
            routePageDrawWaypoint(twMap, currentRouteMapping);
        }

        //GLog.write("back in routePageDisplayRouteOnMap");
        
        // ROUTE TO NEXT CALC SECTION
        
        //GLog.write("currentRouteMapping: " + currentRouteMapping);
        var routeToNext         = routeMappingGetRouteToNext(currentRouteMapping);
        //GLog.write("routeToNext: " + routeToNext);
        var routePointsElement  = routeToNextGetRoutePoints(routeToNext);
        var nextRouteMapping    = routeGetAdjacentRouteMapping(routeXml, routeMappingGetPosition(currentRouteMapping), 1, false);
        
        //GLog.write("routePointsElement: " + routePointsElement);
        var routePoints         = routePointsElement.getElementsByTagName("routePoint");
       // GLog.write("routePointsCount: " + routePoints.length);
        
        var position = routeMappingGetPosition(currentRouteMapping);
        //GLog.write("position: " + position + " num route points: " + routePoints.length + "\n");

        if (routePoints.length == 0 && nextRouteMapping != null 
        /* && 
              (routeMappingGetTypeId(currentRouteMapping) == kRouteMapping_WaypointType || routeMappingGetTypeId(nextRouteMapping) == kRouteMapping_WaypointType) */ )
        {
            twMap["recomputeStatus"][position] = 0;
            directionsRecomputes++;
            
            //GLog.write("recomputing directions between " + routeMappingGetPosition(currentRouteMapping) + " and " + routeMappingGetPosition(nextRouteMapping)  + "\n");            
            var directions = routePageLoadGDirections(twMap, currentRouteMapping, nextRouteMapping);
        } else
        {
            twMap["recomputeStatus"][position] = 1;
        }

        if (firstRouteMapping == currentRouteMapping && routeMappingGetTypeId(firstRouteMapping) == kRouteMapping_WaypointType)
            twMap["waypoints"][position].setImage("/ui/dd-start.png");        
        else if (nextRouteMapping == null)
            twMap["waypoints"][position].setImage("/ui/dd-end.png");
        else
            twMap["waypoints"][position].setImage("/ui/images/yellow-marker.png");
        //GLog.write("end of loop");

    }

    //GLog.write("firstRouteMapping: " + firstRouteMapping);
    if (firstRouteMapping != null && routeMappingGetTypeId(firstRouteMapping) != kRouteMapping_WaypointType) {
        var startLocation = routeGetStartLocation(routeXml);
        mapDrawWaypoint(twMap, -1, new GLatLng(startLocation["latitude"], startLocation["longitude"]), false);
    }
    
    if (firstRouteMapping == null && twMap["waypoints"][-1] != null) {
        twMap["mapControl"].removeOverlay(twMap["waypoints"][-1]);
        twMap["waypoints"][-1] = null;
    }
    
    checkGDirectionsLoadCompleted(twMap);
    //if (twMap["dirtyRoute"] == 1 && directionsRecomputes == 0)
    //{
    //    GLog.write("immediately saving since no direction recomputes.");
    //    saveRoute(twMap);
    //}
}

function routePageOnGDirectionsLoad(routeMapping)
{
  var twMap = twMaps[0];
  var position = routeMappingGetPosition(routeMapping);
  //GLog.write("Gdir load pos: " + position);
  var directionsControl = twMap["directionsControls"][position];
  routePageDeleteRouting(twMap, routeMapping);
  twMap["recomputeStatus"][position] = 1;

  var polyline = directionsControl.getPolyline();
  //GLog.write("polyline: " + polyline);
  var vertexCount = polyline != null ? polyline.getVertexCount() : 0;

  //GLog.write("vertex count: " + vertexCount);

  if (vertexCount < 1) {
      checkGDirectionsLoadCompleted(twMap);
      return;
  }

  var nextRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], routeMappingGetPosition(routeMapping), 1, false);
  if (nextRouteMapping == null) {
      checkGDirectionsLoadCompleted(twMap);
      return;
  }

  var rmStart = routeMappingGetLocation(routeMapping, 'endLocation');
  var rmEnd = routeMappingGetLocation(nextRouteMapping, 'startLocation');

  var firstVertex = polyline.getVertex(0);
  var firstLocation = locationCreateLocation(firstVertex.lat(),firstVertex.lng());
  var lastVertex = polyline.getVertex(vertexCount - 1);
  var lastLocation = locationCreateLocation(lastVertex.lat(), lastVertex.lng());

  //if either the start or finish is way off RM then drop route points as they are probably not valuable.

  //GLog.write("rmstart lat: " + rmStart.latitude);
  //GLog.write("rmstart longitude: " + rmStart.latitude);

  //GLog.write("firstvertex lat: " + firstLocation.latitude);
  //GLog.write("firstvertex longitude: " + firstLocation.latitude);

  //GLog.write("rmend lat: " + rmEnd.latitude);
  //GLog.write("rmend longitude: " + rmEnd.latitude);

  //GLog.write("lastVertex lat: " + lastLocation.latitude);
  //GLog.write("lastVertex longitude: " + lastLocation.latitude);
  
  var startDelta = locationComputeDistance(firstLocation, rmStart);
  var endDelta = locationComputeDistance(lastLocation, rmEnd);
  var routeMappingGap = locationComputeDistance(rmStart, rmEnd);
  var routePointsDistance = directionsControl.getDistance();

  //GLog.write("startDelta: " + startDelta);
  //GLog.write("endDelta: " + endDelta);

  if (startDelta > 100 || endDelta > 100 || routePointsDistance > 2*routeMappingGap) {
      //GLog.write("too big a gap for routepoints start or end, skipping adding them.");
      checkGDirectionsLoadCompleted(twMap);
      return;
  }
  
  var routeToNext = routeMappingGetRouteToNext(routeMapping);
  //GLog.write("routeToNext: " + routeToNext);

  routeToNextSetDistance(routeToNext, directionsControl.getDistance());

  for (var idx=0; idx < vertexCount; idx++) {
    //GLog.write("adding route to next point");
    var vertex = polyline.getVertex(idx);
    routeToNextAddRoutePoint(routeToNext, vertex, idx);
  }

  checkGDirectionsLoadCompleted(twMap);

}

function checkGDirectionsLoadCompleted(twMap)
{
    if (mapRecomputeFinished(twMap)) {
        //GLog.write("GDirections Load Complete.");
	    routePageDisplayGDirections(twMap);
    }
}

function routePageHighlightSegment(twMap, segment) {
    //GLog.write("routePageHightlightSegment");
    var startIcon = new GIcon();
    startIcon.image = "/ui/dd-start.png";
    startIcon.iconSize = new GSize(32, 32);
    startIcon.iconAnchor = new GPoint(16, 32);

    var endIcon = new GIcon();
    endIcon.image = "/ui/dd-end.png";
    endIcon.iconSize = new GSize(32, 32);
    endIcon.iconAnchor = new GPoint(16, 32);

    //GLog.write("startLoc: " + segment.startLocation);
    //GLog.write("endLoc: " + segment.endLocation);
    segment.startMarker = new GMarker(locationCreateGLatLng(segment.startLocation), startIcon);
    segment.endMarker = new GMarker(locationCreateGLatLng(segment.endLocation), endIcon);

    twMap["mapControl"].addOverlay(segment.startMarker);
    twMap["mapControl"].addOverlay(segment.endMarker);
}

function routePageUnhighlightSegment(twMap, segment) {
   // GLog.write("routePageUnhightlightSegment");
    if (segment.startMarker != null) {
        twMap["mapControl"].removeOverlay(segment.startMarker);
        twMap["mapControl"].removeOverlay(segment.endMarker);
        segment.startMarker = null;
        segment.endMarker = null;
    }
}

/*
function routePageDisplaySegmentHighlight(twMap, routeMapping)
{
    var startLocation = routeMappingGetLocation(routeMapping, 'startLocation');
    var endLocation   = routeMappingGetLocation(routeMapping, 'endLocation');

    var startMarkerLocation = new GLatLng(startLocation["latitude"], startLocation["longitude"]);
    var endMarkerLocation = new GLatLng(endLocation["latitude"], endLocation["longitude"]);
   
    var startIcon = new GIcon();
    startIcon.image = "/ui/dd-start.png"; 
    startIcon.iconSize = new GSize(32, 32);
    startIcon.iconAnchor = new GPoint(16,16);

    var endIcon = new GIcon();   
    endIcon.image = "/ui/dd-end.png";
    endIcon.iconSize = new GSize(32, 32);
    endIcon.iconAnchor = new GPoint(16,16);
    
    twMap["startLocationMarker"] = new GMarker(startMarkerLocation, startIcon);
    twMap["endLocationMarker"] = new GMarker(endMarkerLocation, endIcon);                 

    twMap["mapControl"].addOverlay(twMap["startLocationMarker"]);
    twMap["mapControl"].addOverlay(twMap["endLocationMarker"]);
}

function routePageHighlightWaypoint(twMap, position)
{
    var routeMapping = routeGetRouteMappingByPosition(twMap["routeXml"], position);
    if (routeMapping == null)
      return;
      
    var typeId = routeMappingGetTypeId(routeMapping);
    switch(typeId)
    {
        case kRouteMapping_WaypointType: 
        {
            twMap["waypoints"][position].setImage("/ui/images/yellow-marker.png");
            break;
        }
        
        case kRouteMapping_RouteType:
        case kRouteMapping_SegmentType:
        {
            routePageDisplaySegmentHighlight(twMap, routeMapping);
            break;
        }
    }    

}

function routePageUnhighlightWaypoint(twMap, position)
{
    var routeMapping = routeGetRouteMappingByPosition(twMap["routeXml"], position);
    if (routeMapping == null)
      return;
      
    var typeId = routeMappingGetTypeId(routeMapping);
    switch(typeId)
    {
        case kRouteMapping_WaypointType:
        {
            var firstRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], 0, -1, true);
            var lastRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], 0, 1, true);

            if (routeMapping == firstRouteMapping)
              twMap["waypoints"][position].setImage("/ui/dd-start.png");
            else if (routeMapping == lastRouteMapping)
              twMap["waypoints"][position].setImage("/ui/dd-end.png");
            else
              twMap["waypoints"][position].setImage("/ui/images/red-marker.png");
            break;
        }
        
        case kRouteMapping_RouteType:
        case kRouteMapping_SegmentType:
        {  
          if (twMap["startLocationMarker"] != null)
            twMap["mapControl"].removeOverlay(twMap["startLocationMarker"]);

          if (twMap["endLocationMarker"] != null)
            twMap["mapControl"].removeOverlay(twMap["endLocationMarker"]);
            
          break;
        }
    }    
}
*/
function mapRecomputeFinished(twMap)
{
    var currentPosition = 0;
    
    for (currentRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], 0, -1, true);
         currentRouteMapping != null;
         currentRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], currentPosition, 1, false))
    {
        currentPosition = routeMappingGetPosition(currentRouteMapping);
        if (twMap["recomputeStatus"][currentPosition] == 0)
        {
          //GLog.write("position " + currentPosition + " not finished.");
          return false;
        }
    }
    
    return true;
}

function routePageOnGDirectionsError(routeMapping)
{
    var twMap = twMaps[0];
    var position = routeMappingGetPosition(routeMapping);

    //GLog.write("GDirections query failed for position: " + routeMappingGetPosition(routeMapping));
    twMap["recomputeStatus"][position] = 1;

    checkGDirectionsLoadCompleted(twMap);
}

function routePointToLocation(routePoint) {
    
}

function routePageDisplayGDirections(twMap)
{
    //GLog.write("routePageDisplayGDirections ENTRY");

    var firstRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], 0, -1, true);
    //GLog.write("first entry:  " + routeMappingGetPosition(firstRouteMapping));

    var distance = 0.0;
    for (currentRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], 0, -1, true);
         currentRouteMapping != null;
         currentRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], currentPosition, 1, false))
    {
        currentPosition = routeMappingGetPosition(currentRouteMapping);
        var nextRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], currentPosition, 1, false);

        var rmDistance = routeMappingGetDistance(currentRouteMapping);
        //GLog.write("Route mapping: " + routeMappingGetPosition(currentRouteMapping));
        distance = distance + parseFloat(rmDistance);

        //if (twMap["directionsControls"][currentPosition] != null && twMap["directionsControls"][currentPosition].getDistance() != null) {
        //    distance = distance + parseFloat(twMap["directionsControls"][currentPosition].getDistance().meters);
        //    GLog.write("Adding route points distance: " + parseFloat(twMap["directionsControls"][currentPosition].getDistance().meters));
        //}
           
       var routeToNext = routeMappingGetRouteToNext(currentRouteMapping);
       var pointCount = routeToNextGetRoutePointCount(routeToNext);
       var vertexes = new Array();
       var lastPosition = 0;
       var lastLocation = null;
       var currentLocation = null;
       //GLog.write("pointCount: " + pointCount);

       for (var idx=0; idx < pointCount; idx++)
       {
            var routePoint = routeToNextGetRoutePoint(routeToNext, idx);
            var latitude = routePointGetLatitude(routePoint);
            var longitude = routePointGetLongitude(routePoint);
            var position = routePointGetPosition(routePoint);
            lastPosition = position;
            vertexes[position] = new GLatLng(latitude, longitude);

            currentLocation = locationCreateLocation(latitude, longitude);
            if (lastLocation != null) {
                distance += locationComputeDistance(lastLocation, currentLocation);
                //GLog.write("new distance: " + distance);
            }
            lastLocation = currentLocation;
        }

        if (nextRouteMapping != null) {

            if (lastPosition == 0) {
                var currentEndLocation = routeMappingGetEndLocation(currentRouteMapping);
                vertexes[lastPosition] = new GLatLng(currentEndLocation["latitude"], currentEndLocation["longitude"]);
		if (lastLocation != null)
                  distance += locationComputeDistance(lastLocation, currentEndLocation);
                lastLocation = currentEndLocation;
                pointCount++;
            }
            var nextStartLocation = routeMappingGetStartLocation(nextRouteMapping);
            vertexes[++lastPosition] = new GLatLng(nextStartLocation["latitude"], nextStartLocation["longitude"]);
            if (lastLocation != null)
              distance += locationComputeDistance(lastLocation, nextStartLocation);
            pointCount++;
        }
        
        if (twMap["polyline"][currentPosition] == null)
        {
            if (twMap["polyline"][currentPosition] != undefined) {
               twMap["mapControl"].removeOverlay(twMap["polyline"][currentPosition]);
               twMap["polyline"][currentPosition] = null;
           }
            
           if (pointCount > 0) {
             //GLog.write("vertexes: " + vertexes);
             twMap["polyline"][currentPosition] = new GPolyline(vertexes, "#5555ff", 4, 0.6);
             twMap["mapControl"].addOverlay(twMap["polyline"][currentPosition]);
           }
        }
    }

    //GLog.write("distance: " + distance);        
    km = distance / 1000;

    $("totalDistance").innerHTML = Math.round(km * 10) / 10 + " km | " + Math.round(kmToMiles(km) * 10) / 10 + " mi";
}

function routePageLoadGDirections(twMap, startRouteMapping, nextRouteMapping)
{
    var startLocation = routeMappingGetLocation(startRouteMapping, 'endLocation');
   // GLog.write("start location latitude: " + startLocation["latitude"] + " longitude: " + startLocation["longitude"]);
    var endLocation   = routeMappingGetLocation(nextRouteMapping, 'startLocation');
  //  GLog.write("end location latitude: " + endLocation["latitude"] + " longitude: " + endLocation["longitude"]);

    var startPosition = routeMappingGetPosition(startRouteMapping);
    //GLog.write("loading directions from start position:  " + startPosition);
    twMap["directionsControls"][startPosition] = new GDirections(/*twMap["mapControl"]*/ null);

    GEvent.addListener(twMap["directionsControls"][startPosition], "load", function()  { routePageOnGDirectionsLoad(startRouteMapping); });
    GEvent.addListener(twMap["directionsControls"][startPosition], "error", function() { routePageOnGDirectionsError(startRouteMapping); });

    var startLocationAsString = locationToString(startLocation);
    var endLocationAsString = locationToString(endLocation);
    
   // var directionsQueryString = "from:41.895390,12.482010 to:41.883380,12.484990";
    
    var directionsQueryString = "from:" + startLocationAsString + " to:" + endLocationAsString;

    //GLog.write("directions query :" + directionsQueryString);
    
    twMap["directionsControls"][startPosition].load(directionsQueryString, {getPolyline: true}); 
    return twMap["directionsControls"][startPosition];      
}

function routePageMoveWaypoint(twMap, position, latitude, longitude)
{
    // 1 -> 3 -> *6* -> 7   ====>   1 -> 3R -> 6R -> 7

    var routeXml = twMap["routeXml"];

    // delete any directionsControl from previous entry 

    if (routeXml == null)
    {
        //GLog.write("routeXml is null in routePageMoveWaypoint");
        return;
    }
    
    var movedRouteMapping = routeGetRouteMappingByPosition(routeXml, position);
    if (movedRouteMapping == null)
    {
        //GLog.write("moved route mapping is null!");
        return;
    }
    
    var previousRouteMapping = routeGetAdjacentRouteMapping(routeXml , position, -1, false);
    
    //GLog.write("previousRouteMapping:  " + previousRouteMapping);
    //GLog.write("previousRouteMapping pos:  " + routeMappingGetPosition(previousRouteMapping));
   
    if (previousRouteMapping != null)
      routePageDeleteRouting(twMap, previousRouteMapping);
    
    //GLog.write("movedRouteMapping pos:  " + position);
        //GLog.write("movedRouteMapping:  " + movedRouteMapping);
    routePageDeleteRouting(twMap, movedRouteMapping);

    var waypoint = routeMappingGetWaypoint(movedRouteMapping);
    //GLog.write("move location lat: " + latitude + " long:" + longitude);
    
    waypointSetLatitude(waypoint, latitude);
    waypointSetLongitude(waypoint, longitude);
    
    routeMappingSetStartLocation(movedRouteMapping, latitude, longitude);
    routeMappingSetEndLocation(movedRouteMapping, latitude, longitude);
    
    // update waypoint location in routeXml
    // recalc directions from previous entry to new location

    routePageMarkDirty();
    routePageDisplayRoute(twMap);
    
}

function routePageRemove(twMap, position)
{
    // 1 -> 3 -> *6* -> 7   ====>   1 -> 3R -> 7

    var routeXml = twMap["routeXml"];

    var currentRouteMapping = routeGetRouteMappingByPosition(routeXml, position);

    var previousRouteMapping = routeGetAdjacentRouteMapping(routeXml, position, -1, false);
    var previousRouteMappingPosition = routeMappingGetPosition(previousRouteMapping);

    // delete any route points from previous entry and current entry since it will now be calced to the next route entry
    routePageDeleteRouting(twMap, previousRouteMapping);
    if (twMap["polyline"][previousRouteMappingPosition] != null) {
        //GLog.write("routePageRemove removing overlay for position " + previousRouteMappingPosition);

        twMap["mapControl"].removeOverlay(twMap["polyline"][previousRouteMappingPosition]);
        twMap["polyline"][previousRouteMappingPosition] = null;
    }

    if (twMap["polyline"][position] != null) {
        twMap["mapControl"].removeOverlay(twMap["polyline"][position]);
        twMap["polyline"][position] = null;
    }

    var type = routeMappingGetTypeId(currentRouteMapping);

    if (type == kRouteMapping_TrackType) {
        var rangeXml = routeMappingGetRange(currentRouteMapping);
        var rangeId = rangeGetId(rangeXml);

        var range = twMap["ranges"][rangeId];
        twMap["mapControl"].removeOverlay(range.polyline);
    } else if (type == kRouteMapping_SegmentType) {
        var segmentId = routeMappingGetMemberId(currentRouteMapping);
        var segment = twMap["segments"][segmentId];
        segment.inRoute = 0;
        mapDrawSegment(twMap, segment);
    }
    
    // remove the waypoint for this entry.

    if (twMap["waypoints"][position] != null) {

        twMap["mapControl"].removeOverlay(twMap["waypoints"][position]);
        twMap["waypoints"][position] = null;
    }
    
    // delete the route entry   
    routeDeleteRouteMappingByPosition(routeXml, position);

    routePageMarkDirty();
    routePageDisplayRoute(twMap);
    
}

/*
function routePageMoveUp(twMap, position)
{
    // 1 -> 3 -> *6* -> 7   ====>   1R -> 6R -> 3R -> 7
    // delete any directionsControl from current entry, previous entry, and previous entry before that.
    // swap positions of previous entry and current entry
    // recalc directions for curr-2, curr-1, curr

    var routeXml = twMap["routeXml"];

    var currentRouteMapping = routeGetRouteMappingByPosition(routeXml, position);
    if (currentRouteMapping == null)
      return;
    
    var previousRouteMapping = routeGetAdjacentRouteMapping(routeXml, position, -1, false);
    if (previousRouteMapping == null)
      return;
      
    routePageDeleteRouting(twMap, currentRouteMapping);
    routePageDeleteRouting(twMap, previousRouteMapping);

    var previousPosition = routeMappingGetPosition(previousRouteMapping);

    var previous2RouteMapping = routeGetAdjacentRouteMapping(routeXml, previousPosition, -1, false);
    if (previous2RouteMapping != null)
      routePageDeleteRouting(twMap, previous2RouteMapping);
       
    routeMappingSwapPosition(twMap, currentRouteMapping, previousRouteMapping);
    twMap["dirtyRoute"] = 1;
    routePageDisplayRoute(twMap);

}

function routePageMoveDown(twMap, position)
{
    // 1 -> *3* -> 6 -> 7   ====>   1R -> 6R -> 3R -> 7
    // delete any directionsControl from current entry, previous entry, and next entry before that. 
    // swap positions of previous entry and current entry
    
    var routeXml = twMap["routeXml"];
    
    var currentRouteMapping = routeGetRouteMappingByPosition(routeXml, position);
    if (currentRouteMapping == null)
       return;
    
    var nextRouteMapping = routeGetAdjacentRouteMapping(routeXml, position, 1, false);
    if (nextRouteMapping == null)
      return;
      
    routePageDeleteRouting(twMap, nextRouteMapping);
    routePageDeleteRouting(twMap, currentRouteMapping);
    
    var previousRouteMapping = routeGetAdjacentRouteMapping(routeXml, position, -1, false);
    if (previousRouteMapping != null)
      routePageDeleteRouting(twMap, previousRouteMapping);
    
    routeMappingSwapPosition(twMap, currentRouteMapping, nextRouteMapping);
    twMap["dirtyRoute"] = 1;
    routePageDisplayRoute(twMap);
}

function routePageReverseRouteMapping(twMap, position)
{
    // 1 -> *3* -> 6 -> 7  ===>  1R -> 3' -> 6 -> 7
    
    var routeXml = twMap["routeXml"];

    var currentRouteMapping = routeGetRouteMappingByPosition(routeXml, position);
    if (currentRouteMapping == null)
       return;
    routePageDeleteRouting(twMap, currentRouteMapping);

    // delete directionControl from previous entry

    var previousRouteMapping = routeGetAdjacentRouteMapping(routeXml, position, -1, false);
    if (previousRouteMapping != null)
      routePageDeleteRouting(twMap, previousRouteMapping);

    // reverse forward element of routeMapping
    
    routeMappingReverse(currentRouteMapping);
    twMap["dirtyRoute"] = 1;

    routePageDisplayRoute(twMap);
}
*/

function routePageDisplayRoute(twMap)
{
    //routePageDisplayOverview(twMap);
    //routePageDisplayRouteComponents(twMap);
    //GLog.write("routePageDisplayRoute: " + twMap["routeXml"]);
    routePageDisplayActivityStatistics(twMap);
    routePageDisplayRouteOnMap(twMap);
    //GLog.write("routePageDisplayRoute");
    //$("saveRoute").disabled = true;
    //$("revertRoute").disabled = true;
    //$("downloadRoute").disabled = false;
    //$("cloneRoute").disabled = false;
    //$("googleEarth").disabled = false;
}

/*
function routePageDisplayRouteComponents(twMap)
{
    $("routeComponents").innerHTML = routeGetRouteMappingsHtml(twMap);
}
*/

function routePageMarkDirty() {

    //GLog.write("routePageRouteRemoveStaleItems");
    twMaps[0]["dirtyRoute"] = 1;

    $("activityStatistics").innerHTML = "When you have finished making changes, save the route to get updated time estimates.";
    $("elevationGraph").innerHTML = "When you have finished making changes, save the route and Trailguru will recompute the elevation profile for this route in the background.   The elevation profile will be available within 15 minutes by reloading this page.";
    $("saveRoute").disabled = false;
    $("revertRoute").disabled = false;
    $("downloadRoute").disabled = true;
    $("cloneRoute").disabled = true;
    $("googleEarth").disabled = true;
}

function routePageMarkClean() {

    $("saveRoute").disabled = true;
    $("revertRoute").disabled = true;
    $("downloadRoute").disabled = false;
    $("cloneRoute").disabled = false;
    $("googleEarth").disabled = false;
}

function routePageDisplayActivityStatistics(twMap)
{
    $("activityStatistics").innerHTML = routeGetActivityStatsHtml(twMap);
}

/*
function routePageDisplayOverview(twMap)
{
    // display general summary

    //$("totalDistance").innerHTML    = metersToString(routeGetDistance(twMap), false);
    //$("totalAscent").innerHTML      = metersToString(routeGetTotalAscent(twMap), true);
    //$("totalDescent").innerHTML = metersToString(routeGetTotalDescent(twMap), true);
    //$("minimumElevation").innerHTML = metersToString(routeGetMinimumElevation(twMap), true);
    //$("maximumElevation").innerHTML = metersToString(routeGetMaximumElevation(twMap), true);
}
*/

function routePageDeleteRouting(twMap, routeMapping)
{
    var position = routeMappingGetPosition(routeMapping);
    if (twMap["polyline"][position] != null)
    {
      twMap["mapControl"].removeOverlay(twMap["polyline"][position]);
      twMap["polyline"][position] = null;
    }
    
    routeMappingDeleteRoutePoints(routeMapping);
}

function routePageAddSegment(segmentId)
{
    //GLog.write("adding segment to route: " + segmentId);

    var twMap = twMaps[0];
    var segment = twMap["segments"][segmentId];
    segment.inRoute = 1;

    var lastRouteMapping = routeGetAdjacentRouteMapping(twMap["routeXml"], 0, 1, true);

    var forward = 1;
    var position = -1;
    if (lastRouteMapping != null) {
      //  GLog.write("lastRouteMapping is not null");
        position = routeMappingGetPosition(lastRouteMapping);

        var previousEndPosition = routeMappingGetEndLocation(lastRouteMapping);

        var distanceToStart = locationComputeDistance(previousEndPosition, segment.startLocation);
        //GLog.write("distanceToStart: " + distanceToStart);
        var distanceToEnd = locationComputeDistance(previousEndPosition, segment.endLocation);
        //GLog.write("distanceToEnd: " + distanceToEnd);

        if (distanceToStart < distanceToEnd) {
            forward = 1;
          //  GLog.write("adding segment in forward direction");
        } else {
            forward = 0;
           // GLog.write("adding segment in reverse direction");
        }
    }
    
    position++;     // get next position
   // GLog.write("new segment will be at position: " + position);
    routeAddSegment(twMap["routeXml"], segment, forward, position);

    //GLog.write("segment markerLocation: " + markerLocation.lat() + " lng: " + markerLocation.lng());
    
    routePageMarkDirty();
    routePageDisplayRoute(twMap);
}

// ROUTE XML FUNCTIONS 
// ===================

function routeSetEditPerms(editPerms) {

    var twMap = twMaps[0];
    setElementValue(twMap["routeXml"], "editPerms", editPerms);
}

function routeGetRouteMappingFromGDirections(directionsObject)
{
    var twMap = twMaps[0];  
    for (position in twMap["directionControls"])
    {
        if (twMap["routeXml"] == null)
        {
            //GLog.write("routeXml in routeGetRouteMappingFromGDirections is null");
        }
        
        if (twMap["directionControls"][position] == directionsObject)
          return routeGetRouteMappingByPosition(twMap["routeXml"], position);
    }
    
    return null;
}

function routeGetStartLocation(routeXml) {
    var startLocationNode = getSubelement(routeXml, 'startLocation');
    return createLocationFromXml(startLocationNode);
}

function routeGetRouteMappingByPosition(routeXml, position)
{
    var routeMappings = routeXml.getElementsByTagName('routeMapping');
    //GLog.write("length: " + routeMappings.length);
    for (idx=0; idx < routeMappings.length; idx++)
    {
        var routeMapping = routeMappings.item(idx);
        var pos = getElementValueFloat(routeMapping, 'position');
        //GLog.write("position: " + pos);    
        if (pos == position)
          return routeMapping;
    }
    
    return null;
}

function routeDeleteRouteMappingByPosition(routeXml, position)
{
    var routeMappings = routeXml.getElementsByTagName('routeMapping');
    //GLog.write("length: " + routeMappings.length);
    for (idx=0; idx < routeMappings.length; idx++)
    {
        var routeMapping = routeMappings.item(idx);
        var pos = getElementValueFloat(routeMapping, 'position');
        //GLog.write("position: " + pos);    
        if (pos == position)
        {
	  //GLog.write("found node, deleting");
          var routeMappingsNode = getSubelement(routeXml, 'routeMappingsXml');
          routeMappingsNode.removeChild(routeMapping);
          return true;
        }
    }
    
    return false;
}

function routeAddWaypoint(routeXml, latitude, longitude) {
    var lastRouteMapping = routeGetAdjacentRouteMapping(routeXml, 0, 1, true);

    var position = 0;
    if (lastRouteMapping != null)
        position = routeMappingGetPosition(lastRouteMapping);

    routeMappingDeleteRoutePoints(lastRouteMapping);
    
    var location = locationCreateLocation(latitude, longitude);
    //GLog.write("routeAddWaypoint: adding route mapping");
    var waypointRouteMapping = routeAddRouteMapping(routeXml, kRouteMapping_WaypointType, null, position + 1, 1, location, location);
    //GLog.write("routeAddWaypoint: adding waypoint");
    var waypointElement = routeMappingAddWaypoint(routeXml, waypointRouteMapping, latitude, longitude);

    return waypointRouteMapping;
}
/*
function routeAddWaypoint(routeXml, latitude, longitude)
{
    GLog.write("routeAddWaypoint latitude: " + latitude + " longitude: " + longitude);
    var lastRouteMapping = routeGetAdjacentRouteMapping(routeXml, 0, 1, true);
    routeMappingDeleteRoutePoints(lastRouteMapping);

    var position = 0;
    if (lastRouteMapping != null)
      position = routeMappingGetPosition(lastRouteMapping);

  var location = locationCreateLocation(latitude, longitude);
  GLog.write("routeAddRouteMapping from routeAddWaypoint");
    var waypointRouteMapping = routeAddRouteMapping(routeXml, kRouteMapping_WaypointType, null, position+1, 1, location, location);
    var waypointElement = routeMappingAddWaypoint(routeXml, waypointRouteMapping, latitude, longitude);
    
    return waypointRouteMapping;
}
*/
function routeAddSegment(routeXml, segment, forward, position) {
    var lastRouteMapping = routeGetAdjacentRouteMapping(routeXml, 0, 1, true);
    routeMappingDeleteRoutePoints(lastRouteMapping);

    var startLocation  = (forward == 1) ? segment.startLocation : segment.endLocation;
    var endLocation    = (forward == 1) ? segment.endLocation   : segment.startLocation;

    var segmentRouteMapping = routeAddRouteMapping(routeXml, kRouteMapping_SegmentType, segment.segment_id, position, forward, startLocation, endLocation);

    return position;
}

function routeGetAdjacentRouteMapping(routeXml, position, direction, wantEndpoint) {

    //GLog.write("in routeGetAdjacentRouteMapping");

    if (routeXml == null)
      return null;
        
    var lastRouteMapping            = null;
    var lastRouteMappingPosition    = null;
    var routeMappings               = routeXml.getElementsByTagName('routeMapping');
    //GLog.write("routeMappings length: " + routeMappings.length);
    var adjacent                    = wantEndpoint ? 1 : -1;

    for (idx=0; idx < routeMappings.length; idx++)
    {
        var routeMapping = routeMappings[idx];
        //GLog.write("routeMapping[" + idx+ "]:" + routeMapping);
        var routeMappingPosition = routeMappingGetPosition(routeMapping);
        
        if ( (wantEndpoint || direction * routeMappingPosition > direction * position) && 
             (lastRouteMappingPosition == null || adjacent * direction * routeMappingPosition > adjacent * direction * lastRouteMappingPosition)  )
        {
            lastRouteMapping = routeMapping;
            lastRouteMappingPosition = routeMappingPosition;
            //GLog.write("new adjacent route mapping position: " + lastRouteMappingPosition);
        }
    }
    
    return lastRouteMapping;
}

function routeGetRouteMappingsHtml(twMap)
{
    return getElementValue(twMap["routeXml"], "routeMappingsHtml");
}

function routeGetDistance(twMap)
{
    return getElementValue(twMap["routeXml"], "totalDistance");
}

function routeGetActivityStatsHtml(twMap)
{
    return getElementValue(twMap["routeXml"], "activityStatsHtml");
}

function routeGetRouteId(twMap) {
    return getElementValue(twMap["routeXml"], "routeId");
}

function routeGetTotalAscent(twMap)
{
    return getElementValue(twMap["routeXml"], "totalAscent");
}

function routeGetTotalDescent(twMap)
{
    return getElementValue(twMap["routeXml"], "totalDescent");
}

function routeGetMaximumElevation(twMap)
{
    return getElementValue(twMap["routeXml"], "maximumElevation");
}

function routeGetMinimumElevation(twMap)
{
    return getElementValue(twMap["routeXml"], "minimumElevation");
}

function routeAddRouteMapping(routeXml, typeId, memberId, position, forward, startLocation, endLocation)
{
    var routeMappingsCollection = routeXml.getElementsByTagName("routeMappingsXml");
    //GLog.write("routeMappingsHTMLCollection length: " + routeMappingsCollection.length);
    var routeMappingsElement = routeMappingsCollection.item(0);
    //GLog.write("routeMappingsElement: " + routeMappingsElement);
    var routeMappingElement = routeXml.createElement('routeMapping');

    var routeToNextElement = routeXml.createElement('routeToNext');
    routeMappingElement.appendChild(routeToNextElement);
    
    var routePointsElement = routeXml.createElement('routePoints');
    routeToNextElement.appendChild(routePointsElement);
    
    routeMappingElement.appendChild( createElementWithText(routeXml, 'typeId', typeId) );
    routeMappingElement.appendChild( createElementWithText(routeXml, 'memberId', memberId) );
    routeMappingElement.appendChild( createElementWithText(routeXml, 'position', position) );
    routeMappingElement.appendChild( createElementWithText(routeXml, 'forward', forward) );

    routeMappingElement.appendChild( locationCreateLocationElement(routeXml, 'startLocation', startLocation) );
    routeMappingElement.appendChild( locationCreateLocationElement(routeXml, 'endLocation', endLocation) );
       
    routeMappingsElement.appendChild(routeMappingElement);
    return routeMappingElement;
}

// route mapping functions

var kRouteMapping_SegmentType   = 1;
var kRouteMapping_RouteType     = 2;
var kRouteMapping_WaypointType  = 3;
var kRouteMapping_TrackType     = 4;

function routeMappingGetLocation(routeMapping, locationType)
{
    //GLog.write("locationType: " + locationType);
    var locationElement = getSubelement(routeMapping, locationType);
    //GLog.write("locationElement: " + locationElement);
    var location = new Array();
    
    var latitude = getElementValueFloat(locationElement, "latitude");
    //GLog.write("latitude: " + latitude);
    location["latitude"] = getElementValueFloat(locationElement, "latitude");
    location["longitude"] = getElementValueFloat(locationElement, "longitude");
    
    return location;
}

function routeMappingGetDistance(routeMapping) {
    if (routeMappingGetTypeId(routeMapping) == kRouteMapping_TrackType) {
      var rangeXml = routeMappingGetRange(routeMapping);
      var distance = rangeGetDistance(rangeXml);
      //GLog.write("track distance: " + distance);
      return distance;
    } else if (routeMappingGetTypeId(routeMapping) == kRouteMapping_SegmentType) {
      var segment = twMaps[0]["segments"][routeMappingGetMemberId(routeMapping)];
      //GLog.write("segment id: " + routeMappingGetMemberId(routeMapping));
      //GLog.write("segment: " + segment);
      var distance = segment != null ? segment.distance : 0;
      //GLog.write("segment distance: " + distance);
      return distance;
    } else {
      //GLog.write("waypoint,nodistance");
      return 0.0;
    }
}

function routeMappingGetPosition(routeMapping) {
    var position = getElementValueInt(routeMapping, "position");
    return position;
}

function routeMappingGetMemberId(routeMapping) {
    return getElementValueInt(routeMapping, "memberId");
}

function routeMappingGetForward(routeMapping) {
    var position = getElementValueInt(routeMapping, "forward");
    return position;
}

function routeMappingGetRange(routeMapping) {
    return getSubelement(routeMapping, "range");
}

function routeMappingSetPosition(routeMapping, position)
{
    setElementValue(routeMapping, "position", position);
}

function routeMappingSetStartLocation(routeMapping, latitude, longitude)
{
    var startLocationNode = getSubelement(routeMapping, 'startLocation');
    
    setElementValue(startLocationNode, 'latitude',  latitude);
    setElementValue(startLocationNode, 'longitude', longitude);
}

function routeMappingSetEndLocation(routeMapping, latitude, longitude)
{
    var endLocationNode = getSubelement(routeMapping, 'endLocation');
    
    setElementValue(endLocationNode, 'latitude',  latitude);
    setElementValue(endLocationNode, 'longitude', longitude);
}

function routeMappingGetStartLocation(routeMapping) {
    var startLocationNode = getSubelement(routeMapping, 'startLocation');
    return createLocationFromXml(startLocationNode);
}

function routeMappingGetEndLocation(routeMapping)
{
    var endLocationNode = getSubelement(routeMapping, 'endLocation');
    return createLocationFromXml(endLocationNode);
}

function routeMappingGetSegment(routeMapping) {
    return getSubelement(routeMapping, 'segment');
}

function routeMappingGetTypeId(routeMapping)
{
   return getElementValueInt(routeMapping, "typeId");
}

function mapSwapByPosition(twMapEntry, position1, position2)
{
    if (twMapEntry == null)
      return;
      
    var entry1 = twMapEntry[position1];
    var entry2 = twMapEntry[position2];
    
    twMapEntry[position2] = entry1;
    twMapEntry[position1] = entry2;
}

function routeMappingSwapPosition(twMap, routeMapping1, routeMapping2)
{
    var routeMapping1Position = routeMappingGetPosition(routeMapping1);
    var routeMapping2Position = routeMappingGetPosition(routeMapping2);
    
    routeMappingSetPosition(routeMapping1, routeMapping2Position);
    routeMappingSetPosition(routeMapping2, routeMapping1Position);
    
    mapSwapByPosition(twMap["recomputeStatus"],     routeMapping1Position, routeMapping2Position);
    mapSwapByPosition(twMap["polyline"],            routeMapping1Position, routeMapping2Position);
    mapSwapByPosition(twMap["directionsControls"],  routeMapping1Position, routeMapping2Position);   
    mapSwapByPosition(twMap["waypoints"],           routeMapping1Position, routeMapping2Position);

    if (routeMappingGetTypeId(routeMapping2) == kRouteMapping_WaypointType) {
        waypointSetDragEndEvent(twMap, routeMapping1Position);
    }

    if (routeMappingGetTypeId(routeMapping1) == kRouteMapping_WaypointType) {
        waypointSetDragEndEvent(twMap, routeMapping2Position);
    }
}

function routeMappingReverse(routeMapping)
{
    var forward = getElementValueInt(routeMapping, "forward");
    if (forward == 1)
      forward = 0;
    else
      forward = 1;
      
    setElementValue(routeMapping, "forward", forward);
    
    var startLocation = routeMappingGetLocation(routeMapping, 'startLocation');
    var endLocation   = routeMappingGetLocation(routeMapping, 'endLocation');
    
    routeMappingSetStartLocation(routeMapping, endLocation["latitude"], endLocation["longitude"]);
    routeMappingSetEndLocation(routeMapping, startLocation["latitude"], startLocation["longitude"]);
}

function routeMappingGetRouteToNext(routeMapping)
{
    return getSubelement(routeMapping, "routeToNext");
}

function routeMappingGetWaypoint(routeMapping)
{
    //GLog.write("routeMapping: " + routeMapping);
    return getSubelement(routeMapping, "waypoint");
}

function routeMappingAddWaypoint(routeXml, routeMapping, latitude, longitude)
{
    //GLog.write("routeXml: " + routeXml);
    //GLog.write("routeMapping: " + routeMapping);
    var waypointElement = routeXml.createElement('waypoint');
    waypointElement.appendChild( createElementWithText(routeXml, 'latitude', latitude) );
    waypointElement.appendChild( createElementWithText(routeXml, 'longitude', longitude) );
    routeMapping.appendChild(waypointElement);
    
    return waypointElement;
}

function routeMappingDeleteRoutePoints(routeMapping)
{
    if (routeMapping == null)
      return;

    var routeToNext = routeMappingGetRouteToNext(routeMapping);
    var routePoints = routeToNextGetRoutePoints(routeToNext);
    deleteSubelements(routePoints);
    
}

/*
function routeMappingAddDirections(routeXml, routeMapping, directions)
{   
      routeMappingDeleteDirections(routeXml, routeMapping);
      
      var routeToNext = routeMapping.createElement('routeToNext');
      routeToNext.appendChild( createElementWithText(routeXml, 'distance', directions.getDistance) );
     
      var directionPoints = routeMapping.createElement('directionPoints');
            
      var polyline = directions.getPolyline();
	  for (idx=0; idx < polyline.getVertexCount(); idx++)
	  {
	    var directionPoint = routeMapping.createElement('directionPoint');
	   
        directionPoint.appendChild( createElementWithText(routeMapping, 'position', idx) );
        	    
	    var vertex = polyline.getVertex(idx);
        directionPoint.appendChild( createElementWithText(routeMapping, 'latitude', vertex.lat()) );
        directionPoint.appendChild( createElementWithText(routeMapping, 'latitude', vertex.lng()) );
        directionPoints.appendChild(directionPoint);
	  }    
	  
	  routeToNext.appendChild(directionPoints);
	  routeMapping.appendChild(routeToNextElement);

      return routeToNext;
}
*/


// range functions

function rangeGetId(rangeXml) {
    return getElementValueInt(rangeXml, "rangeId");
}

function rangeGetEncodedPoints(rangeXml) {
    return getElementValue(rangeXml, "encodedPoints");
}

function rangeGetEncodedLevels(rangeXml) {
    return getElementValue(rangeXml, "encodedLevels");
}

function rangeGetEndLatitude(rangeXml) {
    return getElementValueFloat(rangeXml, "endLatitude");
}

function rangeGetEndLongitude(rangeXml) {
    return getElementValueFloat(rangeXml, "endLongitude");
}

function rangeGetStartLocation(rangeXml) {
    var startLocationNode = getSubelement(rangeXml, 'startLocation');
    return createLocationFromXml(startLocationNode);
}

function rangeGetEndLocation(rangeXml) {
    var endLocationNode = getSubelement(rangeXml, 'endLocation');
    return createLocationFromXml(endLocationNode);
}

function rangeGetDistance(rangeXml) {
    return getElementValueFloat(rangeXml, "distance");
}

// waypoint functions

function waypointSetDragEndEvent(twMap, position) {

    if (twMap["waypoints"][position] == null)
      return;
         
    GEvent.clearListeners(twMap["waypoints"][position], "dragend");
    GEvent.addListener(twMap["waypoints"][position], "dragend",
        function() {
            var latlong = twMap["waypoints"][position].getPoint();
            routePageMoveWaypoint(twMap, position, latlong.lat(), latlong.lng());
            routePageMarkDirty();
        }
    );

}

function waypointGetLatitude(waypoint)
{
    return getElementValueFloat(waypoint, "latitude");
}

function waypointGetLongitude(waypoint)
{
    return getElementValueFloat(waypoint, "longitude");
}

function waypointSetLatitude(waypoint, latitude)
{
    setElementValue(waypoint, "latitude", latitude);
}

function waypointSetLongitude(waypoint, longitude)
{
    setElementValue(waypoint, "longitude", longitude);
}

// routeToNext functions

function routeToNextGetRoutePoints(routeToNext)
{
    var routePoints = getSubelement(routeToNext, "routePoints");
    return routePoints;
}

function routeToNextClearRoutePoints(routeToNext)
{
    var routePoints = routeToNextGetRoutePoints(routeToNext);
    deleteSubelements(routePoints);
}

function routeToNextGetRoutePointCount(routeToNext)
{
    var routePoints = routeToNext.getElementsByTagName('routePoint');
    return routePoints.length;
}

function routeToNextGetRoutePoint(routeToNext, position)
{
    var routePoints = routeToNext.getElementsByTagName('routePoint');
    if (routePoints.length > position)
      return routePoints.item(position);
}

function routeToNextAddRoutePoint(routeToNext, point, position) {

    var twMap = twMaps[0];
    var routeXml = twMap["routeXml"];

    var routePoints = routeToNextGetRoutePoints(routeToNext);
    var routePoint  = routeXml.createElement('routePoint');
    
    routePoint.appendChild(createElementWithText(routeXml, 'pointPosition',  position) );
    routePoint.appendChild(createElementWithText(routeXml, 'elevation', -500));
    routePoint.appendChild(createElementWithText(routeXml, 'latitude', point.lat()));
    routePoint.appendChild(createElementWithText(routeXml, 'longitude', point.lng()) );

    routePoints.appendChild(routePoint);
}

function routeToNextSetDistance(routeToNext, distance)
{
   setElementValue(routeToNext, 'distance', distance);
}

// routePoint functions

function routePointGetLatitude(routePoint)
{
    return getElementValueFloat(routePoint, 'latitude');
}

function routePointGetLongitude(routePoint)
{
    return getElementValueFloat(routePoint, 'longitude');
}

function routePointGetPosition(routePoint)
{
    return getElementValueFloat(routePoint, 'pointPosition');
}

// location functions

function locationDegreesToRadians(degrees)
{
	return degrees * (Math.PI / 180.0);
}

function locationComputeDistance(location1, location2)
{
   if (location1 == null || location2 == null)
     return 0;

   var latitude1 = locationDegreesToRadians(location1.latitude);
   var longitude1 = locationDegreesToRadians(location1.longitude);

   var latitude2 = locationDegreesToRadians(location2.latitude);
   var longitude2 = locationDegreesToRadians(location2.longitude);

   if (latitude1 == latitude2 && longitude1 == longitude2)
     return 0;

   var distance = Math.acos(Math.cos(latitude1) * Math.cos(longitude1) * Math.cos(latitude2) * Math.cos(longitude2) + Math.cos(latitude1) * Math.sin(longitude1) * Math.cos(latitude2) * Math.sin(longitude2) + Math.sin(latitude1) * Math.sin(latitude2)) * 6378.0 * 1000.0;
   if (distance == NaN)
       distance = 0;
   return distance;
}
        
function locationCreateLocationElement(doc, elementName, location)
{
    var locationElement = doc.createElement(elementName);
    locationElement.appendChild( createElementWithText(doc, 'latitude', location["latitude"]) );
    locationElement.appendChild( createElementWithText(doc, 'longitude', location["longitude"]) );
    
    return locationElement;
}

function locationToString(location)
{
    return location["latitude"] + "," + location["longitude"];
}

function locationCreateLocation(latitude, longitude)
{
    var location = new Array();
    location["latitude"] = latitude;
    location["longitude"] = longitude;
    
    return location;
}

function locationCreateGLatLng(location) {
    return new GLatLng(location["latitude"], location["longitude"]);
}

function locationGetLatitude(location)
{
    return getElementValueFloat(location, "latitude");
}

function locationGetLongitude(location)
{
    return getElementValueFloat(location, "longitude");
}

function locationGetSearchType(location)
{
    return getElementValue(location, "searchType");
}

function onLocationSearchSuccess(response, ioargs)
{
    var twMap = twMaps[0];
    var latitude = locationGetLatitude(response);
    var longitude = locationGetLongitude(response);
    var searchType = locationGetSearchType(response);
      	   
    if (latitude == -1 || longitude == -1)
    {
      if (searchType == "keyword")
        alert("Couldn't find a location by that name -- you might try simplifying the entered location");
      return;    	     
    }
	//GLog.write("location: " + latitude + "," + longitude);
    
    var center = new GLatLng(latitude,longitude);
    twMap["mapControl"].setCenter(center);
    twMap["mapControl"].setZoom(11);

    if (twMap["routeName"] != null) {
        routePageAddWaypoint(twMap, latitude, longitude);
    }
}

function onLocationSearchFailure(response, ioargs)
{
    //GLog.write("location search failed. "+ response);
}

// BBOX FUNCTIONS

function bboxGetSegments(bboxXml)
{
    return bboxXml.getElementsByTagName('segment');
}

 // ===========
 // MAP FUNCTIONS

 var twMaps = new Array();
 var twMapsCount = 0;
 
 var twOverlays = new Array( 
                        new Array(1,     "mapBuildTileKmlUrl"), 
                        new Array(2,     "mapBuildTileKmlUrl"),
                        new Array(3,     "mapBuildTileKmlUrl"), 
                        new Array(4,     "mapBuildTileKmlUrl"), 
                        new Array(5,     "mapBuildTileKmlUrl"), 
                        new Array(6,     "mapBuildTileKmlUrl"), 
                        new Array(7,     "mapBuildTileKmlUrl"), 
                        new Array(8,     "mapBuildTileKmlUrl"),
                        new Array(9,     "mapBuildTileKmlUrl"),
                        new Array(10,    "mapBuildTileKmlUrl"),
                        new Array(11,    "mapBuildTileKmlUrl"),
                        new Array(12,    "mapBuildTileKmlUrl"),
                        new Array(13,    "mapBuildTileKmlUrl"),
                        new Array(14,    "mapBuildTileKmlUrl"),
                        new Array(15,    "mapBuildTileKmlUrl"),
                        new Array(16,    "mapBuildTileKmlUrl"),
                        new Array(17,    "mapBuildTileKmlUrl"),
                        new Array(18,    "mapBuildTileKmlUrl"),
                        new Array(19,    "mapBuildTileKmlUrl"), 
                        
                        new Array(1024,  "mapBuildTileKmlUrl"),
                        new Array(1025,  "mapBuildTrackKmlUrl"),         // Track
                        new Array(1026,  "mapBuildSegmentKmlUrl"),       // Highlights
         // Gradients                        
                       //1027:  Trail Segment Links, which is implemented directly not as KML layer
                        new Array(1028,  "mapBuildRouteKmlUrl"),         // Highlights
                        new Array(1029,  "mapBuildPhotosKmlUrl"),

                        // 1030:  Trail Maps:  aka Tile global enable/disable
                        new Array(1031, "mapBuildRoutesKmlUrl"),
                        
                        // 2000 is track placemark checkbox        
                        new Array(2001,   "mapBuildCatTrackKmlUrl"), 
                        new Array(2002,   "mapBuildCatTrackKmlUrl"),
                        new Array(2003,   "mapBuildCatTrackKmlUrl"), 
                        new Array(2004,   "mapBuildCatTrackKmlUrl"), 
                        new Array(2005,   "mapBuildCatTrackKmlUrl"), 
                        new Array(2006,   "mapBuildCatTrackKmlUrl"), 
                        new Array(2007,   "mapBuildCatTrackKmlUrl"), 
                        new Array(2008,   "mapBuildCatTrackKmlUrl"),
                        new Array(2009,   "mapBuildCatTrackKmlUrl"),
                        new Array(2010,   "mapBuildCatTrackKmlUrl"),
                        new Array(2011,   "mapBuildCatTrackKmlUrl"),
                        new Array(2012,   "mapBuildCatTrackKmlUrl"),
                        new Array(2013,   "mapBuildCatTrackKmlUrl"),
                        new Array(2014,   "mapBuildCatTrackKmlUrl"),
                        new Array(2015,   "mapBuildCatTrackKmlUrl"),
                        new Array(2016,   "mapBuildCatTrackKmlUrl"),
                        new Array(2017,   "mapBuildCatTrackKmlUrl"),
                        new Array(2018,   "mapBuildCatTrackKmlUrl"),
                        new Array(2019,   "mapBuildCatTrackKmlUrl")

                           ); 
 
 function mapRemoveMaps()
 {
	twMaps = new Array();
	twMapsCount = 0;
 }
 
 function mapAddMap(div, latitude, longitude, longitude_west, latitude_south, longitude_east, latitude_north, zoom, routeId, routeName, trackHeaderId, segmentId, recenterByIp, trackRange, animationSteps, userId)
 {   
     ///GLog.write("in mapAddMap: " + animationSteps);

     var twMap                      = new Array();
     twMap["idx"]                   = twMapsCount;
     twMap["div"]                   = div;
     twMap["width"]                 = $(div).style.width;
     twMap["height"]                = $(div).style.height;
     twMap["latitude"]              = latitude;
     twMap["longitude"]             = longitude;
     //twMap["markers"]               = new Array();
     twMap["longitude_west"]        = longitude_west;
     twMap["latitude_south"]        = latitude_south;
     twMap["longitude_east"]        = longitude_east;
     twMap["latitude_north"]        = latitude_north;
     twMap["zoom"]                  = zoom;
     twMap["routeId"]               = routeId;
     twMap["routeName"]             = routeName;
     twMap["recenterByIp"]          = recenterByIp;
     twMap["trackRange"]			= trackRange;
     twMap["animationSteps"]		= animationSteps;
     twMap["trackHeaderId"]         = trackHeaderId;
     twMap["segmentId"]             = segmentId;
     twMap["dirtyRoute"]            = 0;
     twMap["overlays"]              = new Array();
     twMap["mapControl"]            = null;
     twMap["googleEarthURL"]        = null;
     twMap["routeXml"]              = null;
     twMap["bboxXml"]               = null;
     twMap["waypoints"]             = new Array();
     twMap["directionsControls"]    = new Array();
     twMap["recomputeStatus"]       = new Array();
     twMap["polyline"]              = new Array();
     
     twMap["startLocationMarker"]   = null;
     twMap["endLocationMarker"]     = null;
     twMap["segments"]              = new Array();
     twMap["ranges"] = new Array();
     twMap["userId"] = userId;

    // twMap["segmentLinks"]        = new Array();

     twMaps[twMapsCount++] = twMap;
 }
 
 function mapUpdateOverlays(twMap) 
 {  
   if (twMap != null) 
   {
     var categoryIdx=0;
     var usingOwnDrawnSegments = false;
    //GLog.write("routeName: " + twMap["routeName"] + " zoom: " + twMap["mapControl"].getZoom());
     
     if (twMap["routeName"] != null && twMap["routeName"] != "" && twMap["mapControl"].getZoom() >= 14) {
//         GLog.write("loading bbox: " + twMap["routeName"]);
         loadBBox(twMap);
         usingOwnDrawnSegments = true;
     } else {
         //GLog.write("undrawing segments");
         mapUndrawSegments(twMap);
     }

     for (categoryIdx = 0; categoryIdx < twOverlays.length; categoryIdx++) {
     
            var overlayArray = twOverlays[categoryIdx];
            var categoryId = overlayArray[0];
            var kmlFunction = overlayArray[1];

            //GLog.write("categoryId: " + categoryId);

            if ($(twMap["div"] + "category1") == null && categoryId != 1025) {
                //GLog.write("no legend and not category=1025, skipping");
                continue;
            }
            if (twMap["overlays"][categoryIdx] != null)
            {
              twMap["mapControl"].removeOverlay(twMap["overlays"][categoryIdx]);
              twMap["overlays"][categoryIdx] = null;
            }

            // don't draw if we are within zoom for routes to own draw segments.
            if (usingOwnDrawnSegments == true && categoryId < 1024) {
                //GLog.write("skipping drawing category: " + categoryId);
                continue;
            }

            // don't draw trail maps if global switch is off.
            if (categoryId < 1024 && ($(twMap["div"] + "category1030") == null || $(twMap["div"] + "category1030").checked == false) ) {
                //GLog.write("skipping category: " + categoryId);
                //GLog.write("id: " + twMap["div"] + "category1030");
                //GLog.write("element: " + $(twMap["div"] + "category1030"));
                //GLog.write("checked: " + $(twMap["div"] + "category1030").checked);
                continue;
            }
                              
            var checkboxId = twMap["div"] + "category" + categoryId;
            //GLog.write("checkboxId: " + checkboxId);
            if ($(checkboxId) == null)
            {
               //GLog.write("checkboxId: " + checkboxId + " doesn't exist");
            }

	        var shiftedCategory = categoryId-2000;
            if (categoryId==1025 && twMap["trackHeaderId"] != null || 
                categoryId==1026 && twMap["segmentId"] != null ||
	            categoryId == 1028 && twMap["routeId"] != null || 
		        categoryId >= 2001 && $(twMap["div"] + "category2000").checked  && $(twMap["div"] + "category" + shiftedCategory).checked ||
                categoryId < 2000 && categoryId != 1025 && categoryId != 1026 && categoryId != 1028 && $(checkboxId).checked)
            {
               var kmlFunctionCall = kmlFunction + "(twMap, " + categoryId + ");";
               //GLog.write("kmlFunctionCall: " + kmlFunctionCall);
               var kmlURL = eval(kmlFunctionCall);  

               if (kmlURL == null)
                 continue;

               //GLog.write("kml url: " + kmlURL);	           
               twMap["overlays"][categoryIdx] = new GGeoXml(kmlURL);
               //GLog.write("overlay: " + twMap["overlays"][categoryIdx]);	           
               twMap["mapControl"].addOverlay(twMap["overlays"][categoryIdx]);
            } 
     }

     if ($(twMap["div"] + "category1027") == null)
         return;
   }
 }
  
 function mapBuildTrackKmlUrl(twMap)
 {
    if (twMap["trackHeaderId"] == null)
      return null;
    
    var url = "http://" + gHost + "/kml/track/" + twMap["trackHeaderId"];
	
    if (twMap["trackRange"] != null)
      url += "/" + twMap["trackRange"];
      
    //GLog.write("in mapBuildTrackKmlUrl: url:" + url);    
    return url;
 }

 function mapBuildTrackBBoxKmlUrl(twMap)
 {
    var bounds = twMap["mapControl"].getBounds();
    var bbox = bounds.getSouthWest().lng() + "," + bounds.getSouthWest().lat() + "," + bounds.getNorthEast().lng() + "," + bounds.getNorthEast().lat();

    // TODO:  add gHost back
    var url = "http://www.trailguru.com/kml/tracks/" + bbox;
    //GLog.write("in mapBuildTileBBoxKmlUrl: tile url:" + url);
    return url;
 }
 
 function mapBuildSegmentKmlUrl(twMap)
 {
    if (twMap["segmentId"] == null)
      return null;
    
    var url = "http://" + gHost + "/kml/segment/" + twMap["segmentId"] + "?showStartFinish=1";
    //GLog.write("in mapBuildSegmentKmlUrl: url:" + url);    
    return url;
 }
 
 function mapBuildPhotosKmlUrl(twMap)
 {
    //GLog.write("in mapBuildPhotosKmlUrl: div:" + twMap["div"]);

    var bounds = twMap["mapControl"].getBounds();
    var bbox = bounds.getSouthWest().lng() + "," + bounds.getSouthWest().lat() + "," + bounds.getNorthEast().lng() + "," + bounds.getNorthEast().lat();

    // TODO:  add gHost back
    var url = "http://www.trailguru.com/kml/photos/" + bbox;
    if (twMap["userId"] != null)
      url = url + "&u=" + twMap["userId"];
        
    //GLog.write("in mapBuildPhotosKmlUrl: tile url:" + url);
    return url;
 }

 function mapBuildTileKmlUrl(twMap, categoryId)
 {
    //GLog.write("in mapBuildTileKmlUrl: div:" + twMap["div"]);

    var bounds = twMap["mapControl"].getBounds();
    var bbox = bounds.getSouthWest().lng() + "," + bounds.getSouthWest().lat() + "," + bounds.getNorthEast().lng() + "," + bounds.getNorthEast().lat();

    // TODO:  add gHost back
    var url = "http://www.trailguru.com/kml/category/" + categoryId + "/" + bbox + "?map=1&zoom=" + twMap["mapControl"].getZoom();
    //GLog.write("in mapBuildTileKmlUrl: tile url:" + url);
    return url;
}
 
 function mapBuildCatTrackKmlUrl(twMap, categoryId) {
     //GLog.write("in mapBuildTileKmlUrl: div:" + twMap["div"]);

     categoryId = categoryId - 2000;
     var bounds = twMap["mapControl"].getBounds();
     var bbox = bounds.getSouthWest().lng() + "," + bounds.getSouthWest().lat() + "," + bounds.getNorthEast().lng() + "," + bounds.getNorthEast().lat();

     // TODO:  add gHost back
     var url = "http://www.trailguru.com/kml/tracks/" + categoryId + "/" + bbox;
     //GLog.write("in mapBuildCatTrackKmlUrl: tile url:" + url);
     return url;
 }

 function mapBuildRoutesKmlUrl(twMap, categoryId) {
     //GLog.write("in mapBuildTileKmlUrl: div:" + twMap["div"]);

     var bounds = twMap["mapControl"].getBounds();
     var bbox = bounds.getSouthWest().lng() + "," + bounds.getSouthWest().lat() + "," + bounds.getNorthEast().lng() + "," + bounds.getNorthEast().lat();

     // TODO:  add gHost back
     var url = "http://www.trailguru.com/kml/routes/" + categoryId + "/" + bbox;
     //GLog.write("in mapBuildRoutesKmlUrl: tile url:" + url);
     return url;
 }
 
 function mapBuildRouteKmlUrl(twMap, categoryId)
 {
    if (twMap["routeId"] == null)
      return null;
    
    var url = "http://www.trailguru.com/kml/route/" + twMap["routeId"] + "?showStartFinish=0";
    //GLog.write("in mapBuildRouteKmlUrl: url:" + url);    
    return url; 
 }
  
 function mapBuildGoogleEarthKmlUrl(twMap)
 {       
    if (twMap["segmentId"] != null)
      return mapBuildSegmentKmlUrl(twMap);
      
    if (twMap["trackHeaderId"] != null)
      return mapBuildTrackKmlUrl(twMap);
    
    if (twMap["routeId"] != null)
      return "/kml/route/" + twMap["routeId"] + "?showWaypoints=1";

/*
    if (useCurrentLocation)
    {
       var bounds = twMap["mapControl"].getBounds();
       bbox = "BBOX=" + bounds.getSouthWest().lng() + "," + bounds.getSouthWest().lat() + "," + bounds.getNorthEast().lng() + "," + bounds.getNorthEast().lat();
    } else
    {
       bbox = "BBOX=" + twMap["longitude_west"] + "," + twMap["latitude_south"] + "," + twMap["longitude_east"] + "," + twMap["latitude_north"];
    }
    
    var kmlURL = "http://" + gHost + "/wiki/kmlForViewpoint2.php?" + kmlArgs + "&map=1&" + bbox;
    
    return kmlURL;
    */
 } 
    
 function mapGetMapById(id)
 {
      for (mapIdx=0; mapIdx < twMapsCount; mapIdx++)
      {
         var twMap = twMaps[mapIdx];
         //GLog.write("mapGetMapById: " + id + " " + twMap["div"]);

         if (twMap["div"] == id)
         {
           //GLog.write("mapGetMapById: found it: " + twMap["div"]);
           return twMap;
         }
      }
      
      //GLog.write("mapGetMapById: DIDN'T find it.");
      return null;
 }


 function onLocationTextKeypress(e) {
   if (window.event) // IE
   {
     keynum = e.keyCode;
   } else if(e.which) // Netscape/Firefox/Opera
   {
     keynum = e.which;
   }
   //GLog.write("onLocationTextKeypress: " + keynum);

   if (keynum == 13) {
       mapRecenterByKeyword();
       return false;
   }
}


 
 function mapRecenterByKeyword()
 {
    var locationText = $("locationText").value;
    var escapedLocationText = escape(locationText);
    var url = "/ws/location/keyword/" + escapedLocationText;
   

    //GLog.write("recenter url: " + url);
    dojo.xhrGet( {  
        url: url, 
        handleAs: "xml",
        timeout: 20000,              // Time in milliseconds
        load: onLocationSearchSuccess,
        error: onLocationSearchFailure
    });
 }
 
 function mapRecenterByIp()
 {
    var url = "/ws/location/ip/";

    dojo.xhrGet( {  
        url: url, 
        handleAs: "xml",
        timeout: 20000,              // Time in milliseconds
        load: onLocationSearchSuccess,
        error: onLocationSearchFailure
    });
 }
 
 function mapOnCheckClick(div, categoryId)
 {
    //GLog.write("in mapOnCheckClick: " + div + " " + categoryId + "\n");

    var twMap = mapGetMapById(div);
    //GLog.write("mapOnCheckClick: categoryId: " + categoryId);
    //GLog.write("mapOnCheckClick: div of found map: " + twMap["div"]);

    if ($(twMap["div"] + "category" + categoryId).checked) {
      //  GLog.write("setting cookie for checked: " + "checked" + categoryId);
        cookieSet("checked" + categoryId, "1", 365, "/");
    } else {
      //  GLog.write("setting cookie for NOT checked: " + "checked" + categoryId);
        cookieSet("checked" + categoryId, "0", 365, "/");
    }
    
    mapUpdateOverlays(twMap);
 }

 function mapSetCheckboxesFromCookies(twMap) 
 {
     //if ($(twMap["div"] + "category1027") == null)
     //  return;
         
     for (categoryIdx=0; categoryIdx < twOverlays.length; categoryIdx++)
     {

        var overlayArray = twOverlays[categoryIdx];
        var categoryId = overlayArray[0];
        
        if (categoryId == 1025 || categoryId == 1026 || categoryId == 1028 || categoryId >= 2000)
          continue;

	// this needs to be in here for blog embedding which has no checkboxes
	if ($(twMap["div"] + "category" + categoryId) == null)
	  continue;

        if (cookieGet("checked" + categoryId) == "1")
          $(twMap["div"] + "category" + categoryId).checked=true;
        else
          $(twMap["div"] + "category" + categoryId).checked=false;
     }
    
    if ($(twMap["div"] + "category1030") != null)
    { 
      if (cookieGet("checked1030") == "1")
        $(twMap["div"] + "category1030").checked=true;
      else
        $(twMap["div"] + "category1030").checked=false;
    }

    if ($(twMap["div"] + "category2000") != null) {
        if (cookieGet("checked2000") == "1")
            $(twMap["div"] + "category2000").checked = true;
        else
            $(twMap["div"] + "category2000").checked = false;
    }
 }

 function mapLegendHighlightElement(baseName) {
     $(baseName).style.display = "inline";
     $(baseName + "Anchor").style.backgroundPosition = "0% -42px";
     $(baseName + "Span").style.backgroundPosition = "100% -42px";
 }

 function mapShowHideLegend(showDiv) {

     $("showMeAnchor").style.backgroundPosition = "";
     $("onWheelsAnchor").style.backgroundPosition = "";
     $("byFootAnchor").style.backgroundPosition = "";
     $("onSnowAnchor").style.backgroundPosition = "";
     $("inWaterAnchor").style.backgroundPosition = "";

     $("showMeSpan").style.backgroundPosition = "";
     $("onWheelsSpan").style.backgroundPosition = "";
     $("byFootSpan").style.backgroundPosition = "";
     $("onSnowSpan").style.backgroundPosition = "";
     $("inWaterSpan").style.backgroundPosition = "";
     
     $("showMe").style.display = "none";
     $("onWheels").style.display = "none";
     $("byFoot").style.display = "none";
     $("onSnow").style.display = "none";
     $("inWater").style.display = "none";

     switch (parseInt(showDiv)) {
         case 1:
         {
             mapLegendHighlightElement("showMe");
             break;
         }
         case 2:
         {
             mapLegendHighlightElement("onWheels");
             break;
         }
         
         case 3:
         {
             mapLegendHighlightElement("byFoot");
             break;
         }

         case 4:
         {
             mapLegendHighlightElement("onSnow");
             break;
         }
         
         case 5:
         {
             mapLegendHighlightElement("inWater");
             break;
         }

     }     
 }

 function mapResizeMap(twMap) {

     var center = twMap["mapControl"].getCenter();
     if ($(twMap["div"]).style.width == twMap["width"]) {
         $(twMap["div"]).style.position = "relative";
         $(twMap["div"]).style.left = "-230px";
         $(twMap["div"]).style.width = "800px";
         $(twMap["div"]).style.height = "700px";
     } else {
         $(twMap["div"]).style.position = "relative";
         $(twMap["div"]).style.left = "0px";
         $(twMap["div"]).style.width = twMap["width"];
         $(twMap["div"]).style.height = twMap["height"];
     }
     twMap["mapControl"].checkResize();
     twMap["mapControl"].panTo(center);
 }
 
 function mapReplayTrack(twMap)
 {
	twMap["animationIdx"] = 0;
	twMap["animationTimer"] = setTimeout("mapAnimationStep()", 5);

    if (twMap["animationMarker"] != null)
	{
	  twMap["mapControl"].removeOverlay(twMap["animationMarker"]);
	  twMap["animationMarker"] = null;
	}
 }
 
 function mapAnimationStep()
 {
    var twMap = twMaps[0];
	if (twMap["animationMarker"] != null)
	{
	  twMap["mapControl"].removeOverlay(twMap["animationMarker"]);
	  twMap["animationMarker"] = null;
	  clearTimeout(twMap["animationTimer"]);
	}
	
	var animationIdx = twMap["animationIdx"];
	if (animationIdx < twMap["animationSteps"].length)
	{
	  var track = twMap["animationSteps"][animationIdx];
      //GLog.write("idx: " + animationIdx + " track: " + track[0] + "," + track[1]);
      var animationLocation = new GLatLng(track[0],track[1]);
 	  
      //var locIcon = new GIcon();
      //locIcon.image = "/ui/dd-start.png";
      //locIcon.iconSize = new GSize(32, 32);
      //locIcon.iconAnchor = new GPoint(16, 16);

      twMap["animationMarker"] = new GMarker(animationLocation/*, locIcon*/);
      twMap["mapControl"].addOverlay(twMap["animationMarker"]);

      twMap["animationIdx"]++;

      twMap["animationTimer"] = setTimeout("mapAnimationStep()", 75);
	} else
	{
	  //twMap["mapControl"].removeOverlay(twMap["animationMarker"]);
	  //twMap["animationMarker"] = null;
	}
 }
 
 function mapOnLoad() {
 
    if (GBrowserIsCompatible()) 
    {
      //GLog.write("in onMapLoad: " + twMapsCount + " maps are present on page.");
      for (mapIdx=0; mapIdx < twMapsCount; mapIdx++)
      {
         var twMap = twMaps[mapIdx];

         //GLog.write("mapcontrol init");
         twMap["mapControl"] = new GMap2(document.getElementById(twMap["div"]), { mapTypes: mapSpecs });
         twMap["mapControl"].addControl(new GSmallMapControl());
         twMap["mapControl"].addControl(new GMapTypeControl());
         twMap["mapControl"].addMapType(G_PHYSICAL_MAP);

         mapSetCheckboxesFromCookies(twMap);
         
         if (twMap["segmentId"] != null)
           $(twMap["div"] + "category1027").checked=true;

         if (twMap["trackHeaderId"] != null && twMap["animationSteps"] != null)
         {
             twMap["mapControl"].addControl(new TrackReplayControl());
             
             if (twMap["div"] != "BlogEmbedMap")
               twMap["mapControl"].addControl(new MapResizeControl());
               
             if (typeof GReverseGeocoder == 'function')
               reverseGeocoderStart(twMap["trackHeaderId"], twMap["mapControl"], (twMap["latitude_south"]+twMap["latitude_north"])/2, (twMap["longitude_west"]+twMap["longitude_east"])/2);
         }

         if (twMap["longitude_east"] != null && twMap["zoom"] == null)
         {
            var dataBounds = new GLatLngBounds(new GLatLng(twMap["latitude_south"],twMap["longitude_west"]), new GLatLng(twMap["latitude_north"],twMap["longitude_east"]));
            twMap["zoom"] = Math.min(twMap["mapControl"].getBoundsZoomLevel(dataBounds), 15);       // use bounds zoom level but to a maximum of zoom level 15

         } else
         {
            if (twMap["zoom"] == null)
              twMap["zoom"] = 2;
         }

         //GLog.write("location: " + twMap["latitude"] + "," + twMap["longitude"] + " zoom:" + twMap["zoom"]);

         var center = new GLatLng(twMap["latitude"],twMap["longitude"]);
	
         if (twMap["routeId"] != null)
           twMap["mapControl"].setCenter(center, twMap["zoom"]);
	else
           twMap["mapControl"].setCenter(center, twMap["zoom"], G_PHYSICAL_MAP);

	     mapUpdateOverlays(twMap);
	     
	     GEvent.addListener(twMap["mapControl"], 'moveend', function() { mapUpdateOverlays(twMap); });
	     if (twMap["routeName"] != null && twMap["routeName"] != "") {
	         //GLog.write("displaying waypoints and directions");
	         loadRoute(twMap);
	     } else {
	       twMap["mapControl"].addControl(new GoogleEarthControl(twMap));
	     }
	
	     if (twMap["latitude"] != null && twMap["longitude"] != null)
           twMap["googleEarthURL"] = mapBuildGoogleEarthKmlUrl(twMap);
	     
	     if (twMap["recenterByIp"] != null)
	       mapRecenterByIp();
      }
    }
 }
 
 function GoogleEarthControl() {}
 
 GoogleEarthControl.prototype = new GControl();
 GoogleEarthControl.prototype.initialize = function(map) {  
 
     var container = document.createElement("div");  
     var googleEarthDiv = document.createElement("div");  
     this.setButtonStyle_(googleEarthDiv);  
     container.appendChild(googleEarthDiv);  
     googleEarthDiv.appendChild(document.createTextNode("View in Google Earth"));  
     var twMap = mapGetMapById(map.getContainer().id);
     GEvent.addDomListener(googleEarthDiv, "click", function() {   
		     window.location = twMap["googleEarthURL"];  
		     });  
	 
	 
     map.getContainer().appendChild(container);  
     return container; 
 }
 
 GoogleEarthControl.prototype.getDefaultPosition = function() {  
	return new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(1, 1));
 }
 
 GoogleEarthControl.prototype.setButtonStyle_ = function(button) {  
    //button.style.textDecoration = "underline";  
    button.style.color = "#000000";  
    button.style.backgroundColor = "white";  
    button.style.font = "small Arial";  
    button.style.border = "1px solid black";  
    button.style.padding = "2px";  
    button.style.marginBottom = "3px";  
    button.style.textAlign = "center";  
    button.style.width = "12em";  
    button.style.cursor = "pointer";
 }

 function MapResizeControl() { }

 MapResizeControl.prototype = new GControl();
 MapResizeControl.prototype.initialize = function(map) {
     var container = document.createElement("div");
     var replayTrackDiv = document.createElement("div");
     this.setButtonStyle_(replayTrackDiv);
     container.appendChild(replayTrackDiv);
     replayTrackDiv.appendChild(document.createTextNode("Resize Map"));
     var twMap = mapGetMapById(map.getContainer().id);
     GEvent.addDomListener(replayTrackDiv, "click", function() {
         mapResizeMap(twMap);
     }
     );

     map.getContainer().appendChild(container);
     return container;
 }

 MapResizeControl.prototype.getDefaultPosition = function() {
     return new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(105, 1));
 }

 MapResizeControl.prototype.setButtonStyle_ = function(button) {
     //button.style.textDecoration = "underline";  
     button.style.color = "#000000";
     button.style.backgroundColor = "white";
     button.style.font = "small Arial";
     button.style.border = "1px solid black";
     button.style.padding = "2px";
     button.style.marginBottom = "3px";
     button.style.textAlign = "center";
     button.style.width = "7em";
     button.style.cursor = "pointer";
 }

 function TrackReplayControl() {}
 
 TrackReplayControl.prototype = new GControl();
 TrackReplayControl.prototype.initialize = function(map) {        
     var container = document.createElement("div");  
     var replayTrackDiv = document.createElement("div");  
     this.setButtonStyle_(replayTrackDiv);  
     container.appendChild(replayTrackDiv);  
     replayTrackDiv.appendChild(document.createTextNode("Replay Track"));
     var twMap = mapGetMapById(map.getContainer().id);  
     GEvent.addDomListener(replayTrackDiv, "click", function() {   
            mapReplayTrack(twMap); 	                                             
         }
     );  
	 
     map.getContainer().appendChild(container); 
     return container; 
 }
 
 TrackReplayControl.prototype.getDefaultPosition = function() {  
	return new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(1, 1));
 }
 
 TrackReplayControl.prototype.setButtonStyle_ = function(button) {  
    //button.style.textDecoration = "underline";  
    button.style.color = "#000000";  
    button.style.backgroundColor = "white";  
    button.style.font = "small Arial";  
    button.style.border = "1px solid black";  
    button.style.padding = "2px";  
    button.style.marginBottom = "3px";  
    button.style.textAlign = "center";  
    button.style.width = "7em";  
    button.style.cursor = "pointer";
 }

var mapSpecs = new Array();
mapSpecs.push(G_NORMAL_MAP);
mapSpecs.push(G_SATELLITE_MAP);
mapSpecs.push(G_HYBRID_MAP);

var trackHeaderId = null;
function reverseGeocoderStart(thid, geocodeMap, latitude, longitude) {
    trackHeaderId = thid;
    var reverseGeocoder = new GReverseGeocoder(geocodeMap);
    GEvent.addListener(reverseGeocoder, "load", reverseGeocoderFoundAddress);
    GEvent.addListener(reverseGeocoder, "error", reverseGeocoderError);
    var point = new GLatLng(latitude, longitude);
    reverseGeocoder.reverseGeocode(point);
}

function reverseGeocoderFoundAddress(placemark) {
    var address = "";
    var prefix = "";

    var idx = placemark.address.indexOf(",");
    if (idx != -1)
        address = placemark.address.substr(idx + 1);
    else
        address = placemark.address;

    //GLog.write("address: " + address);

    address = trim(address);
    
    if (address.length > 0)
      saveTrack(trackHeaderId, address);
}

function reverseGeocoderError() {
    //silently just ignore.
}

function trim(str, chars) {
    return ltrim(rtrim(str, chars), chars);
}

function ltrim(str, chars) {
    chars = chars || "\\s";
    return str.replace(new RegExp("^[" + chars + "]+", "g"), "");
}

function rtrim(str, chars) {
    chars = chars || "\\s";
    return str.replace(new RegExp("[" + chars + "]+$", "g"), "");
}

function confirmDelete() {
    return confirm("Are you sure you want to permanently delete this track?");
}
