/*
	http://www.gebweb.net/optimap/
  These are the implementation-specific parts of the original OptiMap.
  
*/

var tsp; // The BtTspSolver object which handles the TSP computation.
var mode;
var reasons = new Array();
reasons[G_GEO_SUCCESS]            = "Succes";
reasons[G_GEO_MISSING_ADDRESS]    = "Missing Address: L'adresse est absente ou n'a pas de valeur.";
reasons[G_GEO_UNKNOWN_ADDRESS]    = "Unknown Address:  Ne correspond a aucun lieu géographique. Ne peut etre trouve.";
reasons[G_GEO_UNAVAILABLE_ADDRESS]= "Unavailable Address:  Le geocodage de l'adresse donnee ne peut pas etre retourne due a des raisons legales ou contractuelles.";
reasons[G_GEO_BAD_KEY]            = "Bad Key: Cle API Google map non valide.";
reasons[G_GEO_TOO_MANY_QUERIES]   = "Too Many Queries: Requete geocoding de ce site depasse";
reasons[G_GEO_SERVER_ERROR]       = "Server error: Le geocodage demande n'a pas pu etre traitee avec succes.";

/* 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.
 */
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.
 */
function formatDirections(gdir, mode) {
  var addr = tsp.getAddresses();
  var order = tsp.getOrder();
  var retStr = "<table width='100%' border='0' cellspacing='5' cellpadding='5' align='center'>\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><td>"
      + "<img src='../photos/infos_pratiques/itineraire_icons/icon" + colour 
      + number + ".png'></td>"
      + "<td class='titre3'>";
    var headerStr;
    if (addr[order[i]] == null) {
      var prevI = (i == 0) ? gdir.getNumRoutes() - 1 : i-1;
      var latLng = gdir.getRoute(prevI).getEndLatLng();
      headerStr = "(" + gdir.getGeocode(i).Point.coordinates[1] + ", " 
	+ gdir.getGeocode(i).Point.coordinates[0] + ")";
    } else {
	   headerStr = addr[order[i]].substr(0,1).toUpperCase()+	addr[order[i]].substr(1,chaine.length).toLowerCase();
    }
    retStr += headerStr + "</td></tr>\n";
    for (var j = 0; j < route.getNumSteps(); ++j) {
      var classStr = "couleur0";
      if (j % 2 == 0) classStr = "couleur1";
      retStr += "\t<tr><td>&nbsp;</td>"
	+ "<td class='" + classStr + "' valign='top'>"
	+ route.getStep(j).getDescriptionHtml() + " "
	+ route.getStep(j).getDistance().html + "</td></tr>\n";
    }
  }
  if (mode == 0) {
    var headerStr;
    if (addr[order[0]] == null) {
      var prevI = gdir.getNumRoutes() - 1;
      var latLng = gdir.getRoute(prevI).getEndLatLng();
      headerStr = "(" + latLng.lat() + ", " + latLng.lng() + ")";
    } else {
       headerStr = addr[order[0]].substr(0,1).toUpperCase()+	addr[order[0]].substr(1,chaine.length).toLowerCase();
    }
    retStr += "\t<tr><td>"
      + "<img src='../photos/infos_pratiques/itineraire_icons/iconr1.png'></td>"
      + "<td class='titre3'>"
      + headerStr + "</td></tr>\n";
  } 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()]].substr(0,1).toUpperCase()+	addr[order[gdir.getNumRoutes()]].substr(1,chaine.length).toLowerCase();
    }
    retStr += "\t<tr><td>"
      + "<img src='../photos/infos_pratiques/itineraire_icons/icong"
      + (gdir.getNumRoutes() + 1) + ".png'></td>"
      + "<td class='titre3'>"
      + "" 
      + headerStr + "</td></tr>\n";
  }
  retStr += "</table>";
  return(retStr);
}


function drawMarker(latlng, num) {
  var icon;
  var letter = num == 1 ? 'r' : 'b';
  icon = new GIcon(G_DEFAULT_ICON, "../photos/infos_pratiques/itineraire_icons/icon" + letter + num + ".png");
  icon.printImage = "../photos/infos_pratiques/itineraire_icons/icon" + letter + num + ".png";
  icon.mozPrintImage = "../photos/infos_pratiques/itineraire_icons/icon" + letter + num + ".gif";
  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 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();
  // Print shortest roundtrip data:
  var pathStr = "<div class='titre2'>Votre itinéraire  :</div>";
  pathStr += "<div class='informations'>Votre itinéraire est calculé au plus rapide et au plus court ...<br />";
  pathStr += "Durée : " + formatTime(dir.getDuration().seconds) + "<br />";
  pathStr += "Distance : " + formatLength(dir.getDistance().meters) + "</div>";
  document.getElementById("path").innerHTML = pathStr;
  document.getElementById("my_textual_div").innerHTML = formatDirections(dir, mode);

  // 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,"../photos/infos_pratiques/itineraire_icons/iconr1.png");
    myIcn1.printImage = "../photos/infos_pratiques/itineraire_icons/iconr1.png";
    myIcn1.mozPrintImage = "../photos/infos_pratiques/itineraire_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,"../photos/infos_pratiques/itineraire_icons/iconr1.png");
      myIcn1.printImage = "../photos/infos_pratiques/itineraire_icons/iconr1.png";
      myIcn1.mozPrintImage = "../photos/infos_pratiques/itineraire_icons/iconr1.gif";
    } else {
      myIcn1 = new GIcon(G_DEFAULT_ICON,"../photos/infos_pratiques/itineraire_icons/icong" + (i+2) + ".png");
      myIcn1.printImage = "../photos/infos_pratiques/itineraire_icons/icong" + (i+2) + ".png";
      myIcn1.mozPrintImage = "../photos/infos_pratiques/itineraire_icons/icong" + (i+2) + ".gif";
    }
    gebMap.addOverlay(new GMarker(myPt1,myIcn1));
  }
  
  // Replace driving directions with custom made design:
  document.getElementById("my_textual_div").innerHTML 
    = formatDirections(gebDirections, mode); 
  
  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>";
}

function clickedAddList() {
  addList(document.listOfLocations.inputList.value);
}

function addList(listStr) {
  var listArray = listStr.split("\n");
  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 == 2) {
	var lat = parseFloat(latLngArr[0]);
	var lng = parseFloat(latLngArr[1]);
	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);
    }
  }
}

