var maps = {};

function initTools() {
  $(".shape-button").click(function() {
    var parent = $(this).parents(".map-questions");
    var mapId = parent.get(0).id.split("-")[2];

    document.getElementById("map"+mapId).childNodes[0].style.cursor = "";

    maps[mapId].shapeMode = 0;
    maps[mapId].markerMode = 0;

    if ($(this).hasClass("button-blue")) {
      finishShape(maps[mapId]);
    }
    else {
      parent.find(".marker-button.button-blue").val("Place Marker").removeClass("button-blue");
      parent.find(".shape-button.button-blue").val("Draw Area").removeClass("button-blue");
      $(this).val("Click On Map").addClass("button-blue");
      maps[mapId].shapeMode = 1;

      document.getElementById("map"+mapId).childNodes[0].style.cursor = "pointer";
    }
  });

  $(".marker-button").bind("click", function() {
    var parent = $(this).parents(".map-questions");
    var mapId = parent.get(0).id.split("-")[2];

    var enableMarkerMode = !($(this).hasClass("button-blue"));
    parent.find(".marker-button.button-blue").val("Place Marker").removeClass("button-blue");
    parent.find(".shape-button.button-blue").each(function() {
      finishShape(maps[mapId]);
    });
    maps[mapId].shapeMode = 0;
    maps[mapId].markerMode = 0;

    document.getElementById("map"+mapId).childNodes[0].style.cursor = "";

    if (enableMarkerMode) {
      $(this).val("Click On Map").addClass("button-blue");
      maps[mapId].markerMode = 1;

      document.getElementById("map"+mapId).childNodes[0].style.cursor = "pointer";
    }

  });
}

function initVEMap(mapId, lat, lon, newMap) {
  var mapData = {
    mapId: mapId,
    shapePoints: new Array(),
    shapeMode: 0,
    markerMode: 0,
    tmpShape: null,
    startPin: null,
    shapeCount: 0,
    markerCount: 0,
    markers: new Array(),
    shapes: new Array()
  };

  mapData.map = new VEMap("map"+mapId);
  var opts = new VEMapOptions();
  opts.EnableBirdseye = false;
  mapData.map.LoadMap(null, 18, VEMapStyle.Aerial, false, VEMapMode.Mode2D, true, 0, opts);

  initFromFormFields(mapData, false, new VELatLong(lat, lon), 18);

  maps[mapId] = mapData;

  if (newMap) {
    mapData.map.AttachEvent("onclick", ClickHandler);
    mapData.map.AttachEvent("onendpan", ZoomCenterUpdateHandler);
    mapData.map.AttachEvent("onendzoom", ZoomCenterUpdateHandler);
    mapData.map.AttachEvent("onmousemove", MoveHandler);
  }

  ZoomCenterUpdateHandler(undefined, mapData);          // update it now
}

function initViewOnlyVEMap(mapId, lat, lon) {
  var mapData = {
    mapId: mapId,
    shapePoints: new Array(),
    shapeMode: 0,
    markerMode: 0,
    tmpShape: null,
    startPin: null,
    shapeCount: 0,
    markerCount: 0,
    markers: new Array(),
    shapes: new Array()
  };

  mapData.map = new VEMap("map"+mapId);
  var opts = new VEMapOptions();
  mapData.map.LoadMap(new VELatLong(lat, lon), 18, VEMapStyle.Aerial, false, VEMapMode.Mode2D, true, 0, opts);

  initFromFormFields(mapData, true, new VELatLong(lat, lon), 18);

  maps[mapId] = mapData;

  mapData.map.AttachEvent("onendpan", ZoomCenterUpdateHandler);
  mapData.map.AttachEvent("onendzoom", ZoomCenterUpdateHandler);
  mapData.map.AttachEvent("onmousemove", MoveHandler);

  ZoomCenterUpdateHandler(undefined, mapData);          // update it now
}

function endShapeMode(mapData) {
  $("#map-questions-"+mapData.mapId+" .marker-button.button-blue").val("Place Marker").removeClass("button-blue");
  $("#map-questions-"+mapData.mapId+" .shape-button.button-blue").val("Draw Area").removeClass("button-blue");

  mapData.shapeMode = 0;
  mapData.shapePoints = new Array();
  document.getElementById("map"+mapData.mapId).childNodes[0].style.cursor = "";
}

function finishShape(mapData) {
  var container = $("#map-questions-"+mapData.mapId+" .button-blue:first").parent();
  var mapQuestionId = container.attr("id").split("-")[3];

  if (mapData.startPin != null) {
    mapData.map.DeleteShape(mapData.startPin);
    mapData.startPin = null;
  }

  if (mapData.tmpShape != null) {
    mapData.map.DeleteShape(mapData.tmpShape);
    mapData.tmpShape = null;
  }
  
  if (mapData.shapePoints.length >= 3) {
    mapData.shapePoints.push(mapData.shapePoints[0]);         // duplicate the last point to close the shape

    var shape = new VEShape(VEShapeType.Polygon, mapData.shapePoints);

    shape.SetFillColor(new VEColor(200, 0, 0, 0.2));
    shape.SetLineColor(new VEColor(0, 0, 200, 1));
    shape.SetLineWidth(2);
    var areaInSqMiles = calculateArea(shape);
    var areaInSqFeet = areaInSqMiles * 5280 * 5280;
    shape.SetDescription(projectMapQuestions[mapQuestionId].tagDefault+"<br/><b>Area:</b> " + Math.round(areaInSqFeet) + " square feet");
    mapData.map.AddShape(shape);

    // add the shape vertices
    var vertexFields = "";
    $.each(mapData.shapePoints, function(i, n) {
      vertexFields += "<input type=\"hidden\" name=\"projects["+mapData.mapId+"].shapes["+mapData.shapeCount+"].vertices["+i+"].lat\" id=\"projects["+mapData.mapId+"].shapes["+mapData.shapeCount+"].vertices["+i+"].lat\" value=\""+n.Latitude+"\"/>" +
          "<input type=\"hidden\" name=\"projects["+mapData.mapId+"].shapes["+mapData.shapeCount+"].vertices["+i+"].lon\" id=\"projects["+mapData.mapId+"].shapes["+mapData.shapeCount+"].vertices["+i+"].lon\" value=\""+n.Longitude+"\"/>";
    });

    var serviceTypeFields = "";
    $.each(projectMapQuestions[mapQuestionId].serviceTypes, function(i, serviceType) {
      serviceTypeFields += "<input type=\"hidden\" name=\"projects["+mapData.mapId+"].shapes["+mapData.shapeCount+"].serviceTypeIds\" id=\"projects["+mapData.mapId+"].shapes["+mapData.shapeCount+"].serviceTypeIds\" value=\""+serviceType+"\"/>";
    });

    container.find(".map-answers").append("<div class=\"map-shape\">"+
        "<input type=\"text\" name=\"projects["+mapData.mapId+"].shapes["+mapData.shapeCount+"].tag\" id=\"projects["+mapData.mapId+"].shapes["+mapData.shapeCount+"].tag\" value=\""+projectMapQuestions[mapQuestionId].tagDefault+"\" class=\"tag-shape\"/>"+
        "<input type=\"button\" class=\"button\" value=\"Remove\" onclick=\"removeShape('"+mapData.mapId+"', '"+mapData.shapeCount+"');\"/>"+
        "<input type=\"hidden\" name=\"projects["+mapData.mapId+"].shapes["+mapData.shapeCount+"].mapQuestionId\" id=\"projects["+mapData.mapId+"].shapes["+mapData.shapeCount+"].mapQuestionId\" value=\""+mapQuestionId+"\"/>"+
        "<input type=\"hidden\" name=\"projects["+mapData.mapId+"].shapes["+mapData.shapeCount+"].shapeArea\" id=\"projects["+mapData.mapId+"].shapes["+mapData.shapeCount+"].shapeArea\" value=\""+areaInSqFeet+"\"/>"+
        serviceTypeFields+vertexFields+
        "</div>");

    mapData.shapeCount++;
    mapData.shapes.push(shape);
  }

  endShapeMode(mapData);
}

function ClickHandler(e) {
  if (e.leftMouseButton) {
    var mapData = maps[currentProperty];
    var parent = $("#map-questions-"+mapData.mapId);
    var ll;

    if (mapData.markerMode == 1 && parent.find(".button-blue.marker-button").length) {
      ll = mapData.map.PixelToLatLong(new VEPixel(e.mapX, e.mapY));

      if (ll.Latitude == null) {
        ll = (new _xy1).Decode(ll);       // decode it if in birds-eye view
      }

      var container = $(".button-blue:first").parent();
      var mapQuestionId = container.attr("id").split("-")[3];
      var shape = new VEShape(VEShapeType.Pushpin, ll);
      shape.SetDescription(projectMapQuestions[mapQuestionId].tagDefault);
      mapData.map.AddShape(shape);
      mapData.markerMode = 0;
      parent.find(".button-blue").val("Place Marker").removeClass("button-blue");
      document.getElementById("map"+mapData.mapId).childNodes[0].style.cursor = "";

      var serviceTypeFields = "";
      $.each(projectMapQuestions[mapQuestionId].serviceTypes, function(i, serviceType) {
        serviceTypeFields += "<input type=\"hidden\" name=\"projects["+mapData.mapId+"].markers["+mapData.markerCount+"].serviceTypeIds\" id=\"projects["+mapData.mapId+"].markers["+mapData.markerCount+"].serviceTypeIds\" value=\""+serviceType+"\"/>";
      });

      container.find(".map-answers").append("<div class=\"map-marker\">"+
          "<input type=\"text\" name=\"projects["+mapData.mapId+"].markers["+mapData.markerCount+"].tag\" id=\"projects["+mapData.mapId+"].markers["+mapData.markerCount+"].tag\" value=\""+shape.GetDescription()+"\" class=\"tag-marker\"/>"+
          "<input type=\"button\" class=\"button\" value=\"Remove\" onclick=\"removeMarker('"+mapData.mapId+"', '"+mapData.markerCount+"');\"/>"+
          "<input type=\"hidden\" name=\"projects["+mapData.mapId+"].markers["+mapData.markerCount+"].mapQuestionId\" id=\"projects["+mapData.mapId+"].markers["+mapData.markerCount+"].mapQuestionId\" value=\""+mapQuestionId+"\"/>"+
          "<input type=\"hidden\" name=\"projects["+mapData.mapId+"].markers["+mapData.markerCount+"].lat\" id=\"projects["+mapData.mapId+"].markers["+mapData.markerCount+"].lat\" value=\""+ll.Latitude+"\"/>"+
          "<input type=\"hidden\" name=\"projects["+mapData.mapId+"].markers["+mapData.markerCount+"].lon\" id=\"projects["+mapData.mapId+"].markers["+mapData.markerCount+"].lon\" value=\""+ll.Longitude+"\"/>"+
          serviceTypeFields+
          "</div>");

      mapData.markerCount++;
      mapData.markers.push(shape);
    }
    else if (mapData.shapeMode == 1 && parent.find(".button-blue.shape-button").length) {
      // figure out if we're on top of the start pin
      if (mapData.startPin != null && e.elementID != null && e.elementID.indexOf(mapData.startPin.GetID()) == 0) {
        finishShape(mapData);
        return;
      }

      ll = mapData.map.PixelToLatLong(new VEPixel(e.mapX, e.mapY));

      if (ll.Latitude == null) {
        ll = (new _xy1).Decode(ll);       // decode it if in birds-eye view
      }
      mapData.shapePoints.push(ll);

      // create a start pin
      if (mapData.startPin == null) {
        mapData.startPin = new VEShape(VEShapeType.Pushpin, ll);
        mapData.startPin.SetTitle("Click here to complete the area.");
        mapData.startPin.SetCustomIcon("<span class=\"button\">Finish</span>");
        mapData.map.AddShape(mapData.startPin);
      }

      // Polygons require 3 points, until we have them, just draw
      // a line
      if (mapData.tmpShape != null)
        mapData.map.DeleteShape(mapData.tmpShape);

      mapData.tmpShape = new VEShape(VEShapeType.Polyline, [mapData.shapePoints[0], mapData.shapePoints[0]]);
      mapData.map.AddShape(mapData.tmpShape);
      mapData.tmpShape.HideIcon();
    }
  }
}

// Mouse Move handler. Update the polygon everytime the mouse moves.
function MoveHandler(e)
{
  var mapData = maps[currentProperty];

   // if we're currently drawing a polygon, then update the last data point
   // to reflect where the mouse currently is.
   if (mapData.shapeMode == 1 && mapData.tmpShape != null)
   {
      var mouseLatLong = mapData.map.PixelToLatLong(new VEPixel(e.mapX, e.mapY));
      mapData.tmpShape.SetPoints(mapData.shapePoints.concat([mouseLatLong]));
   }
}

function ZoomCenterUpdateHandler(e, mapData) {
  if (mapData == undefined) {
    mapData = maps[currentProperty];
  }

  $("#"+escapeIdForJquery("projects["+mapData.mapId+"].mapZoom")).val(mapData.map.GetZoomLevel());

  var newCtr = mapData.map.GetCenter();

  $("#"+escapeIdForJquery("projects["+mapData.mapId+"].mapCenterLat")).val(newCtr.Latitude);
  $("#"+escapeIdForJquery("projects["+mapData.mapId+"].mapCenterLon")).val(newCtr.Longitude);
}

function aerialView() {
  initFromFormFields(maps[currentProperty], true);
}

function birdseyeView(orientation) {
  var mapData = maps[currentProperty];
  mapData.map.DeleteAllShapes();
  mapData.map.SetBirdseyeScene(mapData.map.GetCenter(), orientation, mapData.map.GetZoomLevel());
}

function calculateArea(shape) {
  // shape has points in latitude/longitude format.  this will only be accurate at the equator.
  // first figure out the average latitude (don't need longitude) for the points.
  var totLat = 0;
  var points = shape.GetPoints();
  for (var i=0; i < points.length; i++) {
    totLat += points[i].Latitude;
  }
  var aveLat = totLat / points.length;

  // now rebuild the xy vertices based on the miles that these actually represent.  we measure from the equator and from 0 longitude.
  var truePoints = new Array(points.length);
  var latitudeMultiplier = 69.0467669;        // 60 nautical miles in "standard" miles
  var longitudeMultiplier = latitudeMultiplier * Math.cos(aveLat * Math.PI / 180);
  for (var i=0; i < points.length; i++) {
    truePoints[i] = new Array(2);
    truePoints[i][0] = points[i].Latitude * latitudeMultiplier;
    truePoints[i][1] = points[i].Longitude * longitudeMultiplier;
  }

  // calculate area from "ordered" vertices
  // ref: http://valis.cs.uiuc.edu/~sariel/research/CG/compgeom/msg00831.html
  var polygonArea = 0;
  for (var i=0; i<truePoints.length; i++) {
    var j = (i+1) % truePoints.length;
    polygonArea += truePoints[i][0] * truePoints[j][1];
    polygonArea -= truePoints[i][1] * truePoints[j][0];
  }
  if (polygonArea < 0) polygonArea = -polygonArea;

  return polygonArea / 2;
}

$(".tag-marker").live("keyup", function () {
  var index = this.id.split(".")[1];
  index = index.substring(index.indexOf("[")+1, index.indexOf("]"));
  maps[currentProperty].markers[index].SetDescription($(this).val());
});

function removeMarker(mapId, markerIndex) {
  $("#"+escapeIdForJquery("projects["+mapId+"].markers["+markerIndex+"].tag")).parent().remove();
  maps[mapId].map.DeleteShape(maps[mapId].markers[markerIndex]);
}

$(".tag-shape").live("keyup", function () {
  var index = this.id.split(".")[1];
  index = index.substring(index.indexOf("[")+1, index.indexOf("]"));
  maps[currentProperty].shapes[index].SetDescription($(this).val() + "<br/><b>Area:</b> " + Math.round(parseFloat($("#"+escapeIdForJquery("projects["+maps[currentProperty].mapId+"].shapes["+index+"].shapeArea")).val())) + " square feet");
});

function removeShape(mapId, shapeIndex) {
  $("#"+escapeIdForJquery("projects["+mapId+"].shapes["+shapeIndex+"].tag")).parent().remove();
  maps[mapId].map.DeleteShape(maps[mapId].shapes[shapeIndex]);
}

function initFromFormFields(mapData, readOnly, defaultCenter, defaultZoom) {
  mapData.map.SetMapStyle(VEMapStyle.Aerial);
  if ($("#"+escapeIdForJquery("projects["+mapData.mapId+"].mapZoom")).val() == 0) {      // new map, just set center to given address with a reasonable zoom level
    mapData.map.SetCenterAndZoom(defaultCenter, defaultZoom);
    return;
  }

  mapData.map.SetCenterAndZoom(new VELatLong($("#"+escapeIdForJquery("projects["+mapData.mapId+"].mapCenterLat")).val(), $("#"+escapeIdForJquery("projects["+mapData.mapId+"].mapCenterLon")).val()), parseInt($("#"+escapeIdForJquery("projects["+mapData.mapId+"].mapZoom")).val()));

  // initialize saved markers
  $("#map-questions-"+mapData.mapId+" .map-marker").each(function(i) {
    var marker = new VEShape(VEShapeType.Pushpin, new VELatLong($("#"+escapeIdForJquery("projects["+mapData.mapId+"].markers["+i+"].lat")).val(), $("#"+escapeIdForJquery("projects["+mapData.mapId+"].markers["+i+"].lon")).val()));
    marker.SetDescription($("#"+escapeIdForJquery("projects["+mapData.mapId+"].markers["+i+"].tag")).val());
    mapData.map.AddShape(marker);
    if (!readOnly) {
      mapData.markers.push(marker);
      mapData.markerCount++;
    }
  });

  // initialize saved shapes
  $("#map-questions-"+mapData.mapId+" .map-shape").each(function(i) {
    var points = new Array();
    var vindex = 0;
    while ($("#"+escapeIdForJquery("projects["+mapData.mapId+"].shapes["+i+"].vertices["+vindex+"].lat")).length > 0) {
      points.push(new VELatLong(parseFloat($("#"+escapeIdForJquery("projects["+mapData.mapId+"].shapes["+i+"].vertices["+vindex+"].lat")).val()), parseFloat($("#"+escapeIdForJquery("projects["+mapData.mapId+"].shapes["+i+"].vertices["+vindex+"].lon")).val())));
      vindex++;
    }

    var aShape = new VEShape(VEShapeType.Polygon, points);
    aShape.SetFillColor(new VEColor(200, 0, 0, 0.2));
    aShape.SetLineColor(new VEColor(0, 0, 200, 1));
    aShape.SetLineWidth(2);
    aShape.SetDescription($("#"+escapeIdForJquery("projects["+mapData.mapId+"].shapes["+i+"].tag")).val()+"<br/><b>Area:</b> " + Math.round(parseFloat($("#"+escapeIdForJquery("projects["+mapData.mapId+"].shapes["+i+"].shapeArea")).val())) +" square feet");
    mapData.map.AddShape(aShape);
    if (!readOnly) {
      mapData.shapes.push(aShape);
      mapData.shapeCount++;
    }
  });
}
