
var MEASURE = 0;
var FACILITY = 1;
var POWER = 2;
var currentMode = MEASURE;
  
var powerfeeds = [];
var facilities = [];
var polygons = [];
 
// initialize jquery functions here
$(document).ready(function(){
    // load google maps
	initializeMap();
	
	/*
		Define listeners for tabs
	*/
	$("#cmd_measure").click(function(){
		currentMode = MEASURE;
		demoTrace();
	});
	
	$("#cmd_facility").click(function(){
		currentMode = FACILITY;
		demoTrace();
	});
	
	$("#cmd_power").click(function(){
		currentMode = POWER;
		demoTrace();
	});
	
	/* Pressing enter while typing an address will look up the address instead of submitting the form */
	$("#address").keypress(function(event) {
		if (event.keyCode == 13)
		{
			codeAddress();
			return false;
		}
		else
		{
			return true;
		}
	});
	
	// append a link map data to a hidden form on the page before submitting the data
	$('form').submit(function () { 
		return true;
	});
	
});
  
  /*  Initializes google map.  This loads the map into "map_canvas" and adds any event listeners
  */
  function initializeMap() {
    var myLatlng = new google.maps.LatLng(43.721830,-96.920957);
	//var myLatlng = new google.maps.LatLng(39.0941974, -87.406797);
    var myOptions = {
      zoom: 3,
      center: myLatlng,
      mapTypeId: google.maps.MapTypeId.HYBRID
    }
    map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
	
	google.maps.event.addListener(map, 'click', onClick);
	google.maps.event.addListener(map, 'click', function() {
        infowindow.close();
    });

  }
  
  function demoTrace()
  {
	var newStatus;
	if (currentMode == MEASURE) {
		newStatus = "Measure";
		$("#cmd_measure").addClass("onColor").removeClass("offColor");
		$("#cmd_facility").addClass("offColor").removeClass("onColor");
		$("#cmd_power").addClass("offColor").removeClass("onColor");
	}
	else if (currentMode == FACILITY) {
		newStatus = "Facility";
		$("#cmd_measure").addClass("offColor").removeClass("onColor");
		$("#cmd_facility").addClass("onColor").removeClass("offColor");
		$("#cmd_power").addClass("offColor").removeClass("onColor");
	}
	else if (currentMode == POWER) {
		newStatus = "Power";
		$("#cmd_measure").addClass("offColor").removeClass("onColor");
		$("#cmd_facility").addClass("offColor").removeClass("onColor");
		$("#cmd_power").addClass("onColor").removeClass("offColor");
	}
	
	$("#current_mode").html(newStatus);
  }
  
  var map;
  

  
  // on map click, call the appropriate function based on the current editing mode
  function onClick(eventArgs)
  {
	switch(currentMode)
	{
		case MEASURE:
			addPolyPoint(eventArgs);
			break;
		case FACILITY:
			addFacility(eventArgs);
			break
		case POWER:
			addPower(eventArgs);
			break;
	}
  }
  
  
  
  var currentPolygon;
  var currentPolyline;
  var currentMarkers;
  
  var polygons = [];
  var polylines = [];
  var markers = [];
  
  function getShapeIndex(marker)
  {
	for (var i in markers)
	{
		var indexOf = markers[i].indexOf(marker);
		if (indexOf != -1)
			return i;
	}
  
	return -1;
  }
  
    
	
var createFirstMarker = false;
var currentIndex = 0;

function addPolygonRow(index, color)
{
	var html = "";
	html += '<tr id="polygon-row-'+index+'">';
	html += '<td><a onclick="centerMap(' + index + ')"><div title="Click to center on this polygon" style="background-color: '+color+'; width:20px; height:20px;"></div></a></td>';
	html += '<td id="polygon-row-'+index+'-size">9001 sq ft</td>';
	html += '<td><a onclick="deletePolygon(' + index + ')"><img title="Click to delete this polygon" src="trash-icon.png"></a></td></tr>';

	$("#polygon-list").append(html).children(':last').hide().fadeIn('fast');
}

function centerMap(index)
{
	var polyCenter = polygons[index].Bounds().getCenter();
	map.setCenter(polyCenter);
}

function deletePolygon(index)
{
	// Deletes incomplete polygons cleanly
	if (polygons.indexOf(currentPolygon) == index)
	{
		currentPolygon = null;
		currentPolyline = null;
	}


	polygons[index].setMap(null);
	polygons[index] = null;
	
	polylines[index].setMap(null);
	polylines[index] = null;
	
	var selectedMarkers = markers[index];
	for (var i in selectedMarkers)
	{
		selectedMarkers[i].setMap(null);
	}
	updateAreaValue();
	
	$('#polygon-row-'+index).empty().remove();
	
}
  
  /* in measure mode:
		add point at click location
		draw polygon
		update area
  */
  function addPolyPoint(eventArgs)
  {  
	// create a new polygon when necessary
	if (currentPolygon == null) {
		  
		  var randomColor = '#'+Math.floor(Math.random()*16777215).toString(16);
		  
		  currentPolygon = new google.maps.Polygon({
			strokeColor: '#000000',
			strokeOpacity: 1.0,
			strokeWeight: 0,
			fillColor: randomColor
		  });
		  currentPolygon.setMap(map);
		  
		  
		  currentPolyline = new google.maps.Polyline({
			strokeColor: '#c00000',
			strokeOpacity: 1.0,
			strokeWeight: 2
		  });
		  currentPolyline.setMap(map);
		  // allows click events on top of polygon
		  google.maps.event.addListener(currentPolygon, 'click', onClick);
		  
		  createFirstMarker = true;
		  
		  currentMarkers = [];
		  
		  polygons[currentIndex] = currentPolygon;
		  polylines[currentIndex] = currentPolyline;
		  markers[currentIndex] = currentMarkers;
		  addPolygonRow(currentIndex, randomColor);
		  
		  currentIndex++;
		  
		  
	}
  
	var path = currentPolygon.getPath();
	path.push(eventArgs.latLng);
	
	path = currentPolyline.getPath();
	path.push(eventArgs.latLng);
  
	var marker =  new google.maps.Marker({
			position: eventArgs.latLng,
			map: map,
			draggable:true
		});
	
	if (createFirstMarker)
	{
		//$("#debug_status").html = shapeIndex.toString();
		google.maps.event.addListener(marker, 'click', function(eventArgs)
			{		
				currentPolyline.setMap(null);
				currentPolygon.setOptions(
					{strokeColor: '#0000c0',
					 strokeOpacity: 1.0,
					 strokeWeight: 2
					});
			
				// clear current to allow new polygon
				currentPolygon = null;
				currentPolyline = null;
			});
			
			createFirstMarker = false;
	}

	currentMarkers.push(marker);
	google.maps.event.addListener(marker, 'dragend', function(eventArgs)
		{
			var shapeIndex = getShapeIndex(marker);
			var indexOf = markers[shapeIndex].indexOf(marker);
			polygons[shapeIndex].getPath().setAt(indexOf, eventArgs.latLng);
			polylines[shapeIndex].getPath().setAt(indexOf, eventArgs.latLng);
			updateAreaValue();
		});
	
	updateAreaValue();
  }
  
  var markers = [];
  
  /* in facility mode:
		add facility marker at location
		update facility count
  */
  function addFacility(eventArgs)
  {
	var marker = new google.maps.Marker({
			position: eventArgs.latLng,
			map: map,
			draggable: true,
			icon: icons["facility"]
			});
			
	facilities.push(marker);
			
    // double click to delete			
	google.maps.event.addListener(marker, 'dblclick', function() {
		var indexOf = facilities.indexOf(marker);
		facilities.splice(marker, 1);
		marker.setMap(null);
		updateFacilityCount();
	});
	
	updateFacilityCount();
  }
  
  /* in power mode:
		add power marker at location
		update power count
  */	
  function addPower(eventArgs)
  {
	var marker = new google.maps.Marker({
			position: eventArgs.latLng,
			map: map,
			draggable: true,
			icon: icons["connection"]
			});
			
	powerfeeds.push(marker);
	
		// Double click to delete
	google.maps.event.addListener(marker, 'dblclick', function() {
		var indexOf = powerfeeds.indexOf(marker);
		powerfeeds.splice(marker, 1);
		marker.setMap(null);
		updatePowerCount();
	});
	
	updatePowerCount();
  }

  /* Updates values in the form based on our map */  
  function updatePowerCount()
  {
	$("#powerfeeds").val(powerfeeds.length);
	
	var html = "Power Feeds";
	for (var i in powerfeeds)
	{
		html += "(" + i + "):" + powerfeeds[i].getPosition() + "<br>";
	}
	$("#power_status").html(html);
	encodeMap();
  }
  
  function updateFacilityCount()
  {
	$("#facilities").val(facilities.length);
	
	var html = "Facilities";
	for (var i in facilities)
	{
		html += "(" + i + "):" + facilities[i].getPosition() + "<br>";
	}
	$("#facility_status").html(html);
	encodeMap();
  }
  
  // Calculate area of all polygons on the map
  function updateAreaValue()
  {
	var area = 0;
	for (var i in polygons)
	{
		if (polygons[i] != null)
		{
			var polySqFt = polygons[i].Area() * 10.7639104; // convert square meters to square feet
			area += polySqFt;
			$('#polygon-row-'+i+'-size').html(polySqFt.toFixed(1) + "sq. ft.");
		}
	}
  
	$("#area").val(area.toFixed(1));
	encodeMap();
  }
  
  function encodeLatLng(latlng)
  {
	return latlng.lat() + "," + latlng.lng();
  }
  
  // Serializes all polygons and markers so we can open this exact map later in a different page
  function encodeMap()
  {
	var html = "";
	html += "center,"
	html += encodeLatLng(map.getCenter());
	html += ",";
	
	for (var i in polygons)
	{
		if (polygons[i] != null) {
			html += "polygon,";
			var path = polygons[i].getPath();
			for (j = 0; j < path.getLength(); j++)
			{
				html += encodeLatLng(path.getAt(j));
				html += ","
			}
		}
		
	}
	
	for (var i in facilities)
	{
		html += "facility,";
		html += encodeLatLng(facilities[i].getPosition());
		html += ","
	}
	
	for (var i in powerfeeds)
	{
		html += "powerfeed,";
		html += encodeLatLng(powerfeeds[i].getPosition());
		html += ","
	}
	
	var encode = $.base64Encode(html);
	var link = 'http://arcflash.biz/mapassist/mapviewer.htm?map=' + encode;
	$("#maplink").val(link);
  }  
  
  /*
	Creates a marker that shows an info window when clicked
  */
  function createMarker(latlng, myicon)
  {
	var marker = new google.maps.Marker({
			position: latlng,
			map: map,
			draggable: true,
			icon: myicon
			});
			
	google.maps.event.addListener(marker, 'dblclick', function() {
		infowindow.setContent(html);
		infowindow.open(map, marker);
	});
			
	return marker;
  }
  
  /*
	Creates a single info window to be used when a marker is clicked
  */
  var infowindow = new google.maps.InfoWindow(
  { 
    size: new google.maps.Size(150,50)
  });

function getVertexCount(polygon)
{
	return polygon.getPath().getLength();
}

function getVertex(polygon, i)
{
	return polygon.getPath().getAt(i);
}
  
// Create the icon images to be used with this app
var icons = new Array();
icons["facility"] = new google.maps.MarkerImage("facility.png",
	// This marker is 32 pixels wide by 34 pixels tall.
	new google.maps.Size(32, 32),
	// The origin for this image is 0,0.
	new google.maps.Point(0,0),
	// The anchor for this image is at 9,34.
	new google.maps.Point(16, 16));
icons["connection"] = new google.maps.MarkerImage("connection.png",
	// This marker is 32 pixels wide by 34 pixels tall.
	new google.maps.Size(32, 32),
	// The origin for this image is 0,0.
	new google.maps.Point(0,0),
	// The anchor for this image is at 9,34.
	new google.maps.Point(16, 16));
 
// === A method which returns the approximate area of a non-intersecting polygon in square metres ===
// === It doesn't fully account for spherical geometry, so will be inaccurate for large polygons ===
// === The polygon must not intersect itself ===
//
// only calculates the area of the first path
//
google.maps.Polygon.prototype.Area = function() {
  var a = 0;
  var j = 0;
  var b = this.Bounds();
  var x0 = b.getSouthWest().lng();
  var y0 = b.getSouthWest().lat();
  for (var i=0; i < this.getPath().getLength(); i++) {
    j++;
    if (j == this.getPath().getLength()) {j = 0;}
    var x1 = this.getPath().getAt(i).distanceFrom(new google.maps.LatLng(this.getPath().getAt(i).lat(),x0));
    var x2 = this.getPath().getAt(j).distanceFrom(new google.maps.LatLng(this.getPath().getAt(j).lat(),x0));
    var y1 = this.getPath().getAt(i).distanceFrom(new google.maps.LatLng(y0,this.getPath().getAt(i).lng()));
    var y2 = this.getPath().getAt(j).distanceFrom(new google.maps.LatLng(y0,this.getPath().getAt(j).lng()));
    a += x1*y2 - x2*y1;
  }
  return Math.abs(a * 0.5);
}

// === A method which returns the bounds as a GLatLngBounds ===
google.maps.Polygon.prototype.Bounds = function() {
  var bounds = new google.maps.LatLngBounds();
  for (var i=0; i < this.getPath().getLength(); i++) {
    bounds.extend(this.getPath().getAt(i));
  }
  return bounds;
}

// === first support methods that don't (yet) exist in v3
google.maps.LatLng.prototype.distanceFrom = function(newLatLng) {
  //var R = 6371; // km (change this constant to get miles)
  var R = 6378100; // meters
  var lat1 = this.lat();
  var lon1 = this.lng();
  var lat2 = newLatLng.lat();
  var lon2 = newLatLng.lng();
  var dLat = (lat2-lat1) * Math.PI / 180;
  var dLon = (lon2-lon1) * Math.PI / 180;
  var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.cos(lat1 * Math.PI / 180 ) * Math.cos(lat2 * Math.PI / 180 ) *
    Math.sin(dLon/2) * Math.sin(dLon/2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  var d = R * c;
  return d;
}


// center map on address
function codeAddress() {

	// show the widget if it is still hidden
	if ($("#map_widget").is(":hidden")){
		$("#map_widget").slideDown();
		google.maps.event.trigger(map, 'resize');
	}
	// find the address
	var geocoder = new google.maps.Geocoder();
    var address = document.getElementById("address").value;
    geocoder.geocode( { 'address': address}, function(results, status) {
      if (status == google.maps.GeocoderStatus.OK) {
        map.setCenter(results[0].geometry.location);
		map.setZoom(16);
       /* var marker = new google.maps.Marker({
            map: map, 
            position: results[0].geometry.location
        });*/
      } else {
        alert("Geocode was not successful for the following reason: " + status);
      }
    });
}

	
	

