var tsp; // The BtTspSolver object which handles the TSP computation.
var mode;
var waypointLabels = new Array();  // Optional labels for each waypoint.
var reasons = new Array();
reasons[G_GEO_SUCCESS]            = "Success";
reasons[G_GEO_MISSING_ADDRESS]    = "Missing Address: The address was either missing or had no value.";
reasons[G_GEO_UNKNOWN_ADDRESS]    = "Unknown Address:  No corresponding geographic location could be found for the specified address.";
reasons[G_GEO_UNAVAILABLE_ADDRESS]= "Unavailable Address:  The geocode for the given address cannot be returned due to legal or contractual reasons.";
reasons[G_GEO_BAD_KEY]            = "Bad Key: The API key is either invalid or does not match the domain for which it was given";
reasons[G_GEO_TOO_MANY_QUERIES]   = "Too Many Queries: The daily geocoding quota for this site has been exceeded.";
reasons[G_GEO_SERVER_ERROR]       = "Server error: The geocoding request could not be successfully processed.";
/* Returns a textual representation of time in the format 
 * "N days M hrs P min Q sec". Does not include days if
 * 0 days etc. Does not include seconds if time is more than
 * 1 hour.
 */
var distance = 0;
function formatTime(seconds) {
  var days;
  var hours;
  var minutes;
  days = parseInt(seconds / (24*3600));
  seconds -= days * 24 * 3600;
  hours = parseInt(seconds / 3600);
  seconds -= hours * 3600;
  minutes = parseInt(seconds / 60);
  seconds -= minutes * 60;
  var ret = "";
  if (days > 0) 
    ret += days + " days ";
  if (days > 0 || hours > 0) 
    ret += hours + " hrs ";
  if (days > 0 || hours > 0 || minutes > 0) 
    ret += minutes + " min ";
  if (days == 0 && hours == 0)
    ret += seconds + " sec";
  return(ret);
}
/* Returns textual representation of distance in the format
 * "N km M m". Does not include km if less than 1 km. Does not
 * include meters if km >= 10.
 */
function formatLength(meters) {
    var km = parseInt(meters / 1000);
  meters -= km * 1000;
  var ret = "";
  if (km > 0) 
    ret += km + " km ";
  if (km < 10)
    ret += meters + " m";
  return(ret);
}
/* Returns an HTML string representing the driving directions.
 * Icons match the ones shown in the map. Addresses are used
 * as headers where available.
 */
var TSParray = new Array();
var latlngDisp = "";
function formatDirections(gdir, mode) {
  var addr = tsp.getAddresses();
  var order = tsp.getOrder();
  var retStr = "<table class='gebddir' border=0 cell-spacing=0>\n";
  for (var i = 0; i < gdir.getNumRoutes(); ++i) {
    var route = gdir.getRoute(i);
    var colour = "g";
    var number = i+1;
    if (number == 1)
      colour = "r";
    retStr += "\t<tr class='heading'><td class='heading' width=40>"
      + "<div class='centered-directions'><img src='../images/"+ number + "_20.png'></div></td>"
      + "<td class='heading'><div class='centered-directions'>";
    var headerStr;
    if (waypointLabels[order[i]] != null && waypointLabels[order[i]] != "") {
        headerStr = waypointLabels[order[i]];       
    } else if (addr[order[i]] != null) {
      headerStr = addr[order[i]];
    } else {
      var prevI = (i == 0) ? gdir.getNumRoutes() - 1 : i-1;
      var latLng = gdir.getRoute(prevI).getEndLatLng();
      latlngDisp += curvehicle + "," + gdir.getGeocode(i).Point.coordinates[1] + ", " + gdir.getGeocode(i).Point.coordinates[0] + "," + Math.round((gdir.getRoute(prevI).getDistance().meters / 1000) * Math.pow(10, 2)) / Math.pow(10, 2) + "#";
      headerStr = "(" + gdir.getGeocode(i).Point.coordinates[1] + ", "	+ gdir.getGeocode(i).Point.coordinates[0] + ")";
	  TSParray.push(latlngDisp);    
  }
  }
  if (mode == 0) {
      var headerStr;
      if (waypointLabels[order[0]] != null && waypointLabels[order[0]] != "") {
          headerStr = waypointLabels[order[0]];
      } else if (addr[order[0]] != null) {
          headerStr = addr[order[0]];
      } else {
          var prevI = gdir.getNumRoutes() - 1;
          var latLng = gdir.getRoute(prevI).getEndLatLng();
          headerStr = "(" + latLng.lat() + ", " + latLng.lng() + ")";
      }
  }
  else if (mode == 1) {
      var headerStr;
      if (addr[order[gdir.getNumRoutes()]] == null) {
          var latLng = gdir.getRoute(gdir.getNumRoutes() - 1).getEndLatLng();
          headerStr = "(" + latLng.lat() + ", " + latLng.lng() + ")";
      } else {
          headerStr = addr[order[gdir.getNumRoutes()]];
      }
      retStr += "\t<tr class='heading'><td class='heading'>"
      + "<div class='centered-directions'><img src='icons/icong"
      + (gdir.getNumRoutes() + 1) + "_20.png'></div></td>"
      + "<td class='heading'>"
      + "<div class='centered-directions'>"
      + headerStr + "</div></td></tr>\n";
  }
  retStr += "</table>";
  latlngDisp = latlngDisp.substring(0, latlngDisp.length - 1) + "|";
  if (LatLngStr.length > 0) {
      var str = LatLngStr.pop();

      startOver();
      addList(str);
      directions(0, false, false);
  }
  else {
      latlngDisp = latlngDisp.substring(0, latlngDisp.length - 1)
      CallServer(latlngDisp, '');
  }
}
function time() {
    setTimeout("delay", 10000);
}
function createTomTomLink(gdir) {
    var addr = tsp.getAddresses();
    var order = tsp.getOrder();
    var addr2 = new Array();
    for (var i = 0; i < order.length; ++i)
        addr2[i] = addr[order[i]];
    var itn = createTomTomItineraryItn(gdir, addr2);
    var retStr = "<form method='GET' action='tomtom.php'>\n";
    retStr += "<input type='hidden' name='itn' value='" + itn + "' />\n";
    retStr += "<input type='submit' value='Send to TomTom' />\n";
    retStr += "</form>\n";
    return retStr;
}
function drawMarker(latlng, num) {
    var icon;
    var letter = num == 1 ? 'r' : 'b';
    icon = new GIcon(G_DEFAULT_ICON, "../images/" + num + "_20.png");
    icon.printImage = "../images/" + num + "_20.png";
    icon.mozPrintImage = "../images/" + num + "_20.png";
    gebMap.addOverlay(new GMarker(latlng, { icon: icon }));
}
function setViewportToCover(waypoints) {
    var bounds = new GLatLngBounds();
    for (var i = 0; i < waypoints.length; ++i) {
        bounds.extend(waypoints[i]);
    }
    gebMap.setCenter(bounds.getCenter());
    gebMap.setZoom(gebMap.getBoundsZoomLevel(bounds));
}
function loadAtStart(lat, lng, zoom) {
    if (GBrowserIsCompatible()) {
        gebMap = new GMap2(document.getElementById("map"));
        directionsPanel = document.getElementById("my_textual_div");
        gebMap.setCenter(new GLatLng(lat, lng), zoom);
        gebMap.addControl(new GLargeMapControl());
        gebMap.addControl(new GMapTypeControl());
        tsp = new BpTspSolver(gebMap, directionsPanel);
        gebDirections = tsp.getGDirections();
        GEvent.addListener(gebDirections, "error", function() {
            alert("Request failed: " + reasons[gebDirections.getStatus().code]);
        });
        GEvent.addListener(gebMap, "click", function(marker, latLng) {
            if (marker == null) {
                tsp.addWaypoint(latLng);
                drawMarker(latLng, tsp.getWaypoints().length);
            } else {
                tsp.removeWaypoint(marker.getPoint());
                gebMap.removeOverlay(marker);
            }
        });
    }
    else {
        alert('Your browser is not compatible with this technology.\nPlease consider upgrading.');
    }
}
function addWaypointWithLabel(latLng, label) {
  waypointLabels.push(label);
  addWaypoint(latLng);
}
function addWaypoint(latLng) {
  tsp.addWaypoint(latLng);
}
function addAddressWithLabel(addr, label) {
  waypointLabels.push(label);
  addAddress(addr);
}
function addAddress(addr) {
  tsp.addAddress(addr, addAddressSuccessCallback);
}
function clickedAddAddress() {
  tsp.addAddress(document.address.addressStr.value, addAddressSuccessCallback2);
}
function addAddressSuccessCallback(address, latlng) {
  if (latlng)
    drawMarker(latlng, tsp.getWaypoints().length);
  else
    alert('Failed to geocode: ' + address);
}
function addAddressSuccessCallback2(address, latlng) {
    if (latlng) {
        drawMarker(latlng, tsp.getWaypoints().length);
        setViewportToCover(tsp.getWaypoints());
    }
    else
        alert('Failed to geocode: ' + address);
}
function startOver() {
    document.getElementById("my_textual_div").innerHTML = "";
    document.getElementById("path").innerHTML = "";
    gebMap.clearOverlays();
    tsp.startOver(); // doesn't clearOverlays or clear the directionsPanel
}
function directions(m, walking, avoid) {
    gebMap.clearOverlays();
    mode = m;
    tsp.setAvoidHighways(avoid);
    if (walking)
        tsp.setTravelMode(G_TRAVEL_MODE_WALKING);
    else
        tsp.setTravelMode(G_TRAVEL_MODE_DRIVING);
    gebMap.clearOverlays();
    if (m == 0) {
        tsp.solveRoundTrip(onSolveCallback);
    }
    else {
        tsp.solveAtoZ(onSolveCallback);
    }
}
function onSolveCallback(myTsp) {
  var dir = tsp.getGDirections();
  var pathStr = "<p>Trip duration: " + formatTime(dir.getDuration().seconds) + "<br>";
  pathStr += "Trip length: " + formatLength(dir.getDistance().meters) + "</p>";
  pathStr += "<input type='button' value='Toggle raw path output' onClick='toggle(\"exportData\");'>";
  document.getElementById("path").innerHTML = pathStr;
  var durStr = "<input type='button' value='Toggle csv durations matrix' onClick='toggle(\"durationsData\");'>";
  document.getElementById("durations").innerHTML = durStr;
  document.getElementById("my_textual_div").innerHTML = formatDirections(dir, mode);
  document.getElementById('lblDistance').innerHTML = document.getElementById('lblDistance').innerHTML + formatTime(dir.getDuration().seconds) + "," + formatLength(dir.getDistance().meters) + "#";
  document.getElementById('lblProgressStatus').innerHTML = 'Route-' + (inc + 1) + '\t is in-progress.!';
  document.getElementById('lblProgressStatus1').innerHTML = 'Route-' + inc + "\t out of\t " + TotalRoutes + '\t is completed...!';
  inc = inc + 1;
  // Remove the standard google maps icons:
  for (var i = 0; i < gebDirections.getNumGeocodes(); ++i) {
      gebMap.removeOverlay(gebDirections.getMarker(i));
  }
  // Add nice, numbered icons instead:
  if (mode == 1) {
      var myPt1 = gebDirections.getRoute(0).getStep(0).getLatLng();
      var myIcn1 = new GIcon(G_DEFAULT_ICON, "icons/iconr1.png");
      myIcn1.printImage = "icons/iconr1.png";
      myIcn1.mozPrintImage = "icons/iconr1.gif";
      gebMap.addOverlay(new GMarker(myPt1, myIcn1));
  }
  for (var i = 0; i < gebDirections.getNumRoutes(); ++i) {
      var route = gebDirections.getRoute(i);
      var myPt1 = route.getEndLatLng();
      var myIcn1;
      if (i == gebDirections.getNumRoutes() - 1 && mode == 0) {
          myIcn1 = new GIcon(G_DEFAULT_ICON, "icons/iconr1.png");
          myIcn1.printImage = "icons/iconr1.png";
          myIcn1.mozPrintImage = "icons/iconr1.gif";
      }
      else {
          myIcn1 = new GIcon(G_DEFAULT_ICON, "icons/icong" + (i + 2) + "_20.png");
          myIcn1.printImage = "icons/icong" + (i + 2) + "_20.png";
          myIcn1.mozPrintImage = "icons/icong" + (i + 2) + "_20.gif";
      }
      gebMap.addOverlay(new GMarker(myPt1, myIcn1));
  }
  // Replace driving directions with custom made design:
  var bestPathLatLngStr = "";
  for (var i = 0; i < gebDirections.getNumGeocodes(); ++i) {
      bestPathLatLngStr += "(" + gebDirections.getGeocode(i).Point.coordinates[1]
      + ", " + gebDirections.getGeocode(i).Point.coordinates[0] + ")\n";
  }
  document.getElementById("exportData_hidden").innerHTML = 
    "<textarea name='outputList' rows='10' cols='40'>" 
    + bestPathLatLngStr + "</textarea><br>";
    var durationsMatrixStr = "";
  var dur = tsp.getDurations();
  for (var i = 0; i < dur.length; ++i) {
      for (var j = 0; j < dur[i].length; ++j) {
          durationsMatrixStr += dur[i][j];
          if (j == dur[i].length - 1) {
              durationsMatrixStr += "\n";
          } else {
              durationsMatrixStr += ", ";
          }
      }
  }
  document.getElementById("durationsData_hidden").innerHTML = 
    "<textarea name='csvDurationsMatrix' rows='10' cols='40'>"
    + durationsMatrixStr + "</textarea><br>";  
}
function clickedAddList() {
    addList(document.getElementById('inputList').value);
}
var LatLngLstLen;
var LatLngStr = new Array();
var curvehicle = "";
var _popup;
var inc = 1;
var TotalRoutes = 0;
function ConstructList(listStr) {
    this._popup = $find('mpProgress');
    this._popup.show();
    inc = 1;
    latlngDisp = "";
    startOver();
    LatLngLstLen = listStr.length;
    var listArray = listStr.split("#|");
    TotalRoutes = listArray.length;
    for (var i = 0; i < listArray.length; ++i) {
        LatLngStr.push(listArray[i]);
    }
     LatLngStr.reverse();  
     var str = LatLngStr.pop();
     addList(str);
     directions(1, false, false);
 }
 function addList(listStr) {
     var listArray = listStr.split("#");
     for (var i = 0; i < listArray.length; ++i) {
         var listLine = listArray[i];
         if (listLine.match(/\(?\s*\-?\d+\s*,\s*\-?\d+/) ||
	listLine.match(/\(?\s*\-?\d+\s*,\s*\-?\d*\.\d+/) ||
	listLine.match(/\(?\s*\-?\d*\.\d+\s*,\s*\-?\d+/) ||
	listLine.match(/\(?\s*\-?\d*\.\d+\s*,\s*\-?\d*\.\d+/)) {
             // Line looks like lat, lng.
             var cleanStr = listLine.replace(/[^\d.,-]/g, "");
             var latLngArr = cleanStr.split(",");
             if (latLngArr.length == 3) {
                 curvehicle = latLngArr[0];
                 var lat = parseFloat(latLngArr[1]);
                 var lng = parseFloat(latLngArr[2]);
                 var latLng = new GLatLng(lat, lng);
                 tsp.addWaypoint(latLng);
                 drawMarker(latLng, tsp.getWaypoints().length);
             }
         } else if (listLine.match(/\S+/)) {
             // Non-empty line that does not look like lat, lng. Interpret as address.
             tsp.addAddress(listLine, addAddressSuccessCallback);
         }
     }
 }