
// Init the variables
var mapMakers = new Array();
var propertyMarkers = new Array();
var map;
var directions;
var vertices = new Array();
var vertexMap = new Array();
var stepToVertex = new Array();
var stepMap = new Array();
var currentLatLng;
var bearing;
var nextBearing;
var nextVertexId;
var nextVertex;
var currentStep;
var carMarker;
var selectedStep = null;
var selectedRoute = null;

function generateRoute(propertylistdiv, startaddressdiv) {
  
  // Order the list
  var list = Sortable.serialize(propertylistdiv);
  list = list.replace(/propertyDiv\[\]=/g, "");
  if (list.length > 0) {
    var arr = list.split("&");
    propertyMarkers = new Array();
    for (var i = 0; i < arr.length; i++) {
      propertyMarkers.push(arr[i]);
    }
  }

  // Generate the route
  var from = document.getElementById(startaddressdiv).value;
  var routetext = "from: " + from;
  for (var i = 0; i < propertyMarkers.length; i++) {
    routetext += " to: " + mapMakers[propertyMarkers[i]].address;
  }

  directions.load(routetext, { preserveViewport: true, getSteps: true });
}

function renderDirections(directionsdiv) {
  document.getElementById(directionsdiv).innerHTML = "";
  vertices = new Array(directions.getNumRoutes());
  vertexMap = new Array(directions.getNumRoutes());
  stepToVertex = new Array(directions.getNumRoutes());
  stepMap = new Array(directions.getNumRoutes());

  for (var i = 0; i < directions.getNumRoutes(); i++) {
    collapseVertices(i, directions.getPolyline());
    renderTextDirections(directionsdiv, i);
  }
}

function collapseVertices(ri, path) {
  var route = directions.getRoute(ri);
  vertices[ri] = new Array();
  vertexMap[ri] = new Array(path.getVertexCount());

  vertices[ri].push(path.getVertex(0));
  vertexMap[ri][0] = 0;

 /* Copy vertices from the polyline to the vertices array
  * skipping any duplicates. Build the vertexMap as we go along */
  for (var i = 1; i < path.getVertexCount(); i++) {
    if (! path.getVertex(i).equals(vertices[ri][vertices[ri].length - 1])) {
      vertices[ri].push(path.getVertex(i));
    }
    vertexMap[ri][i] = vertices[ri].length - 1;
  }

  stepToVertex[ri] = new Array(route.getNumSteps());
  stepMap[ri]      = new Array(vertices[ri].length);

  for (var i = 0; i < route.getNumSteps(); i++) {
    stepToVertex[ri][i] = vertexMap[ri][route.getStep(i).getPolylineIndex()];
  }

  var step = 0;
  for (var i = 0; i < vertices[ri].length; i++) {
    if (stepToVertex[ri][step + 1] == i) {
      step++;
    }
    stepMap[ri][i] = step;
  }
}

function renderTextDirections(directionsdiv, ri) {

  var route = directions.getRoute(ri);

  /* Get the addresses to display at the start and end of the directions */
  var startAddress = route.getStartGeocode().address;
  var   endAddress = route.getEndGeocode().address;
  var theTitle = "";
  if (ri == 0) {
    theTitle = "";
  } else {
    theTitle = mapMakers[propertyMarkers[ri - 1]].title;
  }

  /* Write the start address title, marker, and summary */
  var html  =  getDirectionsWaypointHtml(theTitle, startAddress, mapMakers[propertyMarkers[ri]].title, endAddress, route.getSummaryHtml(), ri);

  /* Build up the textual directions step by step */
  for (var n = 0; n < route.getNumSteps(); n++) {
    html += '<a onclick="selectStep(' + ri + ', ' + n + ')">';
    html += getDivHtml("step_" + ri + "_" + n, "dstep", route.getStep(n).getDescriptionHtml());
    html += '</a>';
  }

  // Fill in the div on the page with the generated HTML
  document.getElementById(directionsdiv).innerHTML += html;
}

function getDirectionsWaypointHtml(starttitle, startaddress, endtitle, endaddress, summary, index) {
  var startaddressline = "";
  if (starttitle.length == 0) {
    starttitle = startaddress;
  } else {
    startaddressline = "<tr><td></td><td class=\"text_small_padded\">" + startaddress + "</td></tr>";
  }
  var letter = String.fromCharCode("A".charCodeAt(0) + (index + 1)); 
  return getDivHtml("wayPoint" + index.toString(), "waypoint", "<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr><td class=\"text_small\"><b>Start:</b></td><td class=\"text_small_padded\">" + starttitle + "</td></tr>" + startaddressline + "<tr><td class=\"text_small\"><b>End:</b></td><td class=\"text_small_padded\">" + endtitle + "</td></tr><tr><td rowspan=\"2\" align=\"center\"><img src=\"http://maps.google.com/intl/en_us/mapfiles/icon_green" + letter + ".png\"/></td><td class=\"text_small_padded\">" + endaddress + "</td></tr><tr><td class=\"text_small_padded\">" + summary + "</td></tr></table>");
}

function getDivHtml(id, cssClass, content) {
  var div = "<div";
  if (id != "") {
    div += ' id="' + id + '"';
  }

  if (cssClass != "") {
    div += ' class="' + cssClass + '"';
  }

  div += '>' + content + '</div>';
  return div;
}

function selectStep(ri, i) {
  var route = directions.getRoute(ri);
  var vertex = vertexMap[ri][route.getStep(i).getPolylineIndex()];
  jumpToVertex(ri, vertex);
}

function jumpToVertex(ri, idx) {
  currentLatLng = vertices[ri][idx];
  nextVertex = vertices[ri][idx + 1];
  nextVertexId = idx + 1;

      bearing = getBearingFromVertex(ri, idx);
  nextBearing = getBearingFromVertex(ri, idx + 1);

  setCarMarkerImage(bearing);
  carMarker.setLatLng(currentLatLng);
  carMarker.show();

  currentStep = stepMap[ri][idx];
  map.panTo(currentLatLng, 16);
  highlightStep(ri, currentStep);
  checkDistanceFromNextVertex(ri);
}

function getBearingFromVertex(ri, n) {
  var origin = vertices[ri][n];
  var destination = vertices[ri][n+1];
  if (destination != undefined) {
    return getBearing(origin, destination);
  } else {
    return null;
  }
}

function getBearing(origin, destination) {
  if (origin.equals(destination)) {
    return null;
  }
  var lat1 = origin.lat().toRad();
  var lat2 = destination.lat().toRad();
  var dLon = (destination.lng()-origin.lng()).toRad();

  var y = Math.sin(dLon) * Math.cos(lat2);
  var x = Math.cos(lat1)*Math.sin(lat2) -
          Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
  return Math.atan2(y, x).toBrng();
}
/**
* Convert an angle in degrees to radians
*/
Number.prototype.toRad = function() {
  return this * Math.PI / 180;
}

/**
* Convert an angle in radians to degrees (signed)
*/
Number.prototype.toDeg = function() {
  return this * 180 / Math.PI;
}

/**
* Convert radians to degrees (as bearing: 0...360)
*/
Number.prototype.toBrng = function() {
  return (this.toDeg()+360) % 360;
}

function setCarMarkerImage(bearing) {
  carMarker.setImage(getArrowUrl(bearing));
}

function getArrowUrl(bearing) {
  var id = (3 * Math.round(bearing / 3)) % 120;
  return "http://maps.google.com/mapfiles/dir_" + id + ".png";
}

function highlightStep(ri, i) {
  /* Remove highlighting from the currently highlighted step */
  if (selectedStep != null) {
    document.getElementById("step_" + selectedRoute + "_" + selectedStep).style.backgroundColor = "white";
  }

  /* Highlight the indicated step as requested */
  document.getElementById("step_" + ri + "_" + i).style.backgroundColor = "#CACAFF";
  selectedStep = i;
  selectedRoute = ri;
}

function checkDistanceFromNextVertex(ri) {
  var d = currentLatLng.distanceFrom(nextVertex);
  var b = getBearing(currentLatLng, nextVertex);
  if (getYawDelta(bearing, b) > 90) {
    incrementVertex(ri);
  }
}

function incrementVertex(ri) {
  if (!vertices[nextVertexId + 1]) {
    /* we are at the end of the route */
    endReached();
  } else {
    nextVertexId++;
    nextVertex = vertices[nextVertexId];

    /* Rotate the vehicle marler to face the new bearing */
        bearing = getBearingFromVertex(ri, nextVertexId - 1);
    nextBearing = getBearingFromVertex(ri, nextVertexId);
    setCarMarkerImage(bearing);

    /* Check if we have reached the next step */
    if (stepMap[ri][nextVertexId - 1] == currentStep) {
    } else {
      currentStep = stepMap[ri][nextVertexId - 1];
      highlightStep(ri, currentStep);
    }
  }
}

function getYawDelta(a, b) {
  var d = Math.abs(sanitiseYaw(a) - sanitiseYaw(b));
  if (d > 180) {
    d = 360 - d;
  }
  return d;
}

function sanitiseYaw(yaw) {
  if (yaw > 360 || yaw < 360) {
    yaw = yaw % 360;
  }
  return yaw;
}

function getCarMarker(start) {
  return new GMarker(start, getArrowIcon(0.0));
}

function getArrowIcon(bearing) {
  var icon = new GIcon();
  icon.image = getArrowUrl(bearing);
  icon.iconSize = new GSize(24, 24);
  icon.iconAnchor = new GPoint(12, 12);
  return icon;
}

function createLocationMarkerIcon() {
  var markerIcon = new GIcon(); 
  markerIcon.image = "http://maps.google.com/mapfiles/kml/pal3/icon55.png";
  markerIcon.shadow = "http://maps.google.com/mapfiles/kml/pal3/icon55s.png";
  markerIcon.iconSize = new GSize(25, 25);
  markerIcon.shadowSize = new GSize(22, 20);
  markerIcon.iconAnchor = new GPoint(16, 16);
  markerIcon.infoWindowAnchor = new GPoint(5, 1);
  return markerIcon;
}

function getMapMarker(theID) {
  for (var i = 0; i < mapMakers.length; i++) {
    if (mapMakers[i].id == theID) {
      return mapMakers[i];
    }
  }
  return null;
}

function getMapMarkerIndex(theID) {
  for (var i = 0; i < mapMakers.length; i++) {
    if (mapMakers[i].id == theID) {
      return i;
    }
  }
  return -1;
}

function showMarker(theID) {
  var theIndex = getMapMarkerIndex(theID);
  if (theIndex > - 1) {
    mapMakers[theIndex].openInfoWindowHtml(mapMakers[theIndex].locationhtml);
    map.setZoom(5);
  }
}

function toggleMarker(theID) {
  var theIndex = getMapMarkerIndex(theID);
  if (theIndex > - 1) {
    if (mapMakers[theIndex].isHidden()) {
      mapMakers[theIndex].show();
    } else {
      mapMakers[theIndex].closeInfoWindow();
      mapMakers[theIndex].hide();
    }
  }
}
/*
function createMarker(theID, title, point, address, propertyhtml, eventshtml, markerurl, iconurl, iconh, iconw, favorite) {
  var marker = new LabeledMarker(point, {icon:createHouseMarkerIcon(),id:theID,address:address,propertyhtml:propertyhtml,locationhtml:"",iconurl:iconurl,iconh:iconh,iconw:iconw,title:title});
  var theIndex = getMapMarkerIndex(theID);
  if (theIndex < 0) {
    mapMakers.push(marker);
    theIndex = (mapMakers.length - 1)
  }
  GEvent.addListener(marker, 'click', function() {
    marker.openInfoWindowHtml(propertyhtml);
  });
  map.addOverlay(marker);
  if (!favorite) {
    marker.hide(); 
  }
  mapMakers[theIndex] = marker;
}
*/

function createLocationMarker(theID, title, point, address, locationhtml) {
  var marker = new LabeledMarker(point, {icon:createLocationMarkerIcon(),id:theID,address:address,propertyhtml:"",locationhtml:locationhtml,iconurl:"",iconh:"",iconw:"",title:title});
  var theIndex = getMapMarkerIndex(theID);
  if (theIndex < 0) {
    mapMakers.push(marker);
    theIndex = (mapMakers.length - 1)
  }
  GEvent.addListener(marker, 'click', function() {
    marker.openInfoWindowHtml(locationhtml);
  });
  map.addOverlay(marker);
  mapMakers[theIndex] = marker;
}

function loadLocationMap(mapid, dataurl, imagesurl, lat, longval) {
  if (GBrowserIsCompatible()) {
    var start = new GLatLng(lat, longval);
    map = new GMap2(document.getElementById(mapid));
    map.setCenter(start, 5);
    map.addControl(new GSmallMapControl());
    map.addControl(new GMapTypeControl());     

    // Load the wineries
    GDownloadUrl(dataurl, function(data) {
      var xml = GXml.parse(data);
      var xmlMarkers = xml.documentElement.getElementsByTagName("marker");
      for (var i = 0; i < xmlMarkers.length; i++) {
        var id = xmlMarkers[i].getAttribute("id");
        var title = xmlMarkers[i].getAttribute("title");
        var address = xmlMarkers[i].getAttribute("address");
        var locationhtml = xmlMarkers[i].childNodes[0].childNodes[0].nodeValue;
        var point = new GLatLng(parseFloat(xmlMarkers[i].getAttribute("lat")),
                                parseFloat(xmlMarkers[i].getAttribute("lng")));
        if (xmlMarkers[i].getAttribute("lat").length > 0) {
          createLocationMarker(id, title, point, address, locationhtml);
        }
      }
      //finishLoadingLocations();
    });
  }
}