/* **********************************************************************************************************************
    FILE: tools.js
    DIRECTORY: scripts/map
    PROJECT: GeoEye
    DATE: June 7, 2008
    AUTHORS: Grant McKenzie
             Ryan Whitley
    DESCRIPTION: Handles the google map tool buttons (pan, point, line, polygon, extent) and their basic functionality.
********************************************************************************************************************** */

var color = "#ff0000";
var featureTable_;
var _listener = null;
var _polygonClosed = false; // Trigger for polygon closed or not
var _polyListener = null; //The listener for drawing a polygon
var _mouseMoveListener = null; //Listening for mouse move events
var _mapExtent = null; // Setting mapExtent as a global variable allows it to be enabled and disabled based on zoom level
var _polygon = null; // Polygon created by the DrawShape tool
var _polygonUpdateCount = 0;  //Hack, since resizing a polygon is adding one listener for each resize.  Cut off at 1
var _follow_marker = null; //pin that follows mouse when point tool is initially selected

/// <summary>
/// Changes the base image of each button based on which tools has been selected
/// </summary>
/// <returns>null</returns>
function select(buttonId) {
    GEvent.trigger(_map.getInfoWindow(), "closeclick"); //Force the window shut if open.
    $("mapPan").style.backgroundImage = "url(images/button-map-drag.gif)"; 
    $("mapMarker").style.backgroundImage = "url(images/button-map-pin.gif)";
    $("mapPoly").style.backgroundImage = "url(images/button-map-polygon.gif)"; 
    //this should be checked to see if extent tool is active.
    ExtentToolStatus(_extentToolOn);


    if (buttonId == "mapPan") {
        $("mapPan").style.backgroundImage = "url(images/button-map-drag-active.gif)"; 
    }
    else if (buttonId == "mapMarker") {
        $("mapMarker").style.backgroundImage = "url(images/button-map-pin-active.gif)"; 
    }
    else if (buttonId == "mapPoly") {
        $("mapPoly").style.backgroundImage = "url(images/button-map-polygon-active.gif)"; 
    }
    else if (buttonId == "mapExtent") {
        $("mapExtent").style.backgroundImage = "url(images/button-map-map-extent-active.gif)"; 
    }
}

/// <summary>
/// Sets the google maps icon properties
/// </summary>
/// <returns>icon</returns>
function getIcon(color) {
  var icon = new GIcon();
  icon.image = "images/map-push-pin.png";
  icon.shadow = "images/map-push-pin-shadow.png";
  icon.iconSize = new GSize(16, 30);
  icon.iconAnchor = new GPoint(5, 32);
  return icon;
}

/// <summary>
/// Gets a Custom Icon for the specified Image Url
/// </summary>
///<params name="url">The url of the icon to be loaded.</params>
/// <returns>icon</returns>
function getCustomIcon(url) {
  var icon = new GIcon();
  icon.image = "images/map-push-pin.png";
  icon.shadow = "images/map-push-pin-shadow.png";
  icon.iconSize = new GSize(16, 30);
  icon.iconAnchor = new GPoint(5, 32);
  return icon;
}

/// <summary>
/// Executes when Polygon tool is selected.
/// Clear overlays and ovelay info div (featuretable)
/// Start drawing the polygon when user clicks on map
/// </summary>
/// <returns>null</returns>
function startShape() {
    try {
          ClearEverything();
          _polygon = new GPolygon([], color, 2, 0.7, color, 0);
          startDrawing("AOI ", function() {
            var cell = this;
            var sqkm = GetSquareKm(_polygon);
            //_foot.SetVLayerDesc("AOI: " + sqkm + " km<sup>2 </sup> ");
            _foot.SetVLayerDesc("AOI (Approx): " + addCommas(sqkm) + " sq.km. ");
            //RW - Updated the geometry, so re-search
            _searchResultsGrid.Clear();
            if(_polygonUpdateCount < 1)
            {
                _searchGeometryObject.SetGeometry(_polygon, "polygon")
                if(SearchByGeometry(_searchGeometryObject))
                { 
                    //Increment now.  Decrement when REST response comes back.  Avoids sending multiple requests.
                    _polygonUpdateCount++;
                }
            }
            cell.innerHTML = "( " + sqkm + " km<sup>2 </sup> )";
          }, color, "polygon");
      }
      catch(e)
      {
            ErrorAlert(CatalogSearchError);
      }
}

/// <summary>
/// Called from 'StartLine()' and 'StartShape()'
/// Accepts geometry object, descriptive name, onUpdate function, color and geometry type
/// Allows user to edit geometry
/// </summary>
/// <returns>null</returns>
function startDrawing(name, onUpdate, color, geomType) {
    try {
          _map.addOverlay(_polygon);
          _polygonClosed = false;
          _polygon.enableDrawing();
          _polygon.enableEditing({onEvent: "mouseover"});
          _polygon.disableEditing({onEvent: "mouseout"});
          GEvent.addListener(_map, "click", function() {
            if (_polygon != null) {
              if (_polygon.getVertexCount() == 23) {
                MapAlert("Your polygon contains 24 vertices, please close polygon before the 30 vertex limit.");
              }
              else if (_polygon.getVertexCount() == 29) {
                MapAlert("Your polygon contains 30 vertices, it will automatically close");
                // alert("count=" + _polygon.getVertexCount());
                _polygon.insertVertex(_polygon.getVertexCount(), _polygon.getVertex(0));
                _polygon.disableEditing();
                GEvent.trigger(_polygon, "endline", function() { // When the polygon is complete...    
                    select("mapPan");
                    _polygonClosed = true;
                    var cells = addFeatureEntry(name, color);
                    _polyListener = GEvent.bind(_polygon, "lineupdated", cells.desc, onUpdate);
                });
              }
            }
          });
           GEvent.addListener(_polygon, "cancelline", function() {  // When there is an error with drawing the polygon (like only 2 it only contains two points
                _map.clearOverlays();
                _polygonClosed = false;
                select("mapPan");
           });
           GEvent.addListener(_polygon, "endline", function() { // When the polygon is complete...
                select("mapPan");
                _polygonClosed = true;
                var cells = addFeatureEntry(name, color);
                _polyListener = GEvent.bind(_polygon, "lineupdated", cells.desc, onUpdate);
           });
      }
      catch(e)
      {
            ErrorAlert(CatalogSearchError);
      }
}

/// <summary>
/// Add overlay information to the info div
/// </summary>
/// <returns>array containing cell and color</returns>
function addFeatureEntry(name, color) {
  currentRow_ = document.createElement("tr");
  var colorCell = document.createElement("td");
  currentRow_.appendChild(colorCell);
  colorCell.style.backgroundColor = color;
  colorCell.style.width = "1em";
  var nameCell = document.createElement("td");
  currentRow_.appendChild(nameCell);
  nameCell.innerHTML = name;
  var descriptionCell = document.createElement("td");
  currentRow_.appendChild(descriptionCell);
  // featureTable_.appendChild(currentRow_);
  return {desc: descriptionCell, color: colorCell};
}

/// <summary>
/// Executes when Point (marker) tool is selected.
/// Clear overlays and ovelay info div (featuretable)
/// Start drawing the point when user clicks on map
/// </summary>
/// <returns>null</returns>
function placeMarker() {
  try
  {
      _foot.ClearFeatureTable();
      _listener = GEvent.addListener(_map, "click", function(overlay, latlng) {
        if (latlng) {
          select("mapPan");
          GEvent.removeListener(_listener);
          _map.clearOverlays();
          var marker = new GMarker(latlng, {icon: getIcon(color), draggable: true});
          _map.addOverlay(marker);
          _foot.SetVLayerDesc("POI: " + Math.round(marker.getLatLng().lat()*10000)/10000 + ", " + Math.round(marker.getLatLng().lng()*10000)/10000);
          _searchGeometryObject.SetGeometry(marker, "marker") //Set the global search marker to this newly created marker
          ExecuteCatalogSearch(marker.getLatLng());  // Search for footprints when marker is placed
          GEvent.addListener(marker, "dragend", function() {
          _map.clearOverlays();
            updateMarker(marker);
            //RW - Execute Point Catalog Search if point is dragged
            _searchGeometryObject.SetGeometry(marker, "marker"); //Set the global search marker to this newly created marker
            ExecuteCatalogSearch(marker.getLatLng()); // Search for footprints when marker is moved
          });
        }
      });
   }
   catch(e)
   {
        ErrorAlert(CatalogSearchError);   
   }
}

/// <summary>
/// Executes when Extent tool is selected.
/// Clear overlays and overlay info div (featuretable)
/// Gets the current map extent, creates polygon, adds polygon to the map
/// Passes extent for footprint search
/// </summary>
/// <returns>null</returns>
function buildExtent() {
	
	try 
	{
	    if(_mouseMoveListener != null){
            GEvent.removeListener(_mouseMoveListener); //remove mouse move listener if active
            _map.removeOverlay(_follow_marker); //Remove the marker
          }
        _map.clearOverlays();
        _polygon = null;
        _foot.ClearFeatureTable();
        // Draw Polygon
        var nw = getLatLonFromPixel(2,2);
        var se = getLatLonFromPixel(_map.getSize().width-4,_map.getSize().height-4);
        var ne = getLatLonFromPixel(2, _map.getSize().height-4);
        var sw = getLatLonFromPixel(_map.getSize().width-4, 2);
        var polygon = new GPolygon([nw,ne,se,sw,nw], color, 5, 1, color, 0.1);
        _map.addOverlay(polygon);
        
        // Compute/Display SqKM
        var sqkm = GetSquareKm(polygon);
        _foot.SetVLayerDesc("AOI (Approx): " + addCommas(sqkm) + " sq.km. ");
        
        _searchGeometryObject.SetGeometry(polygon, "envelope");  //Save for later to add on top of search results.
        SearchByGeometry(_searchGeometryObject); // Search for footprints based on extent
    }
    catch (e)
    {
        //throw CatalogSearchError;
        ErrorAlert(CatalogSearchError);
    }
}

/// <summary>
/// Accepts browser pixel values
/// </summary>
/// <returns>latlong point</returns>
function getLatLonFromPixel(x,y) {
    var swpixel = _map.getCurrentMapType().getProjection().fromLatLngToPixel(_map.getBounds().getSouthWest(),_map.getZoom());
    var nepixel = _map.getCurrentMapType().getProjection().fromLatLngToPixel(_map.getBounds().getNorthEast(),_map.getZoom());
    var latlong = _map.getCurrentMapType().getProjection().fromPixelToLatLng(new GPoint(swpixel.x + x,nepixel.y + y),_map.getZoom());
    var point = new GLatLng(latlong.y, latlong.x);
    return point;
} 

/// <summary>
/// When marker is selected and moved, update position info and optionally change color
/// </summary>
/// <returns>null</returns>
function updateMarker(marker) {
  var latlng = marker.getPoint();
  _foot.SetVLayerDesc("POI: " + Math.round(latlng.y*10000)/10000 + ", " + Math.round(latlng.x*10000)/10000);
}

/// <summary>
/// Create the basic control for the map tools
/// prototype: add it as a new control to google maps
/// prototype.initialize = construct the elements that are inside the control
/// </summary>
/// <returns>null</returns>
function MapToolControl() 
{
}
    MapToolControl.prototype = new GControl();

    MapToolControl.prototype.initialize = function(_map) {
	var container = document.createElement("div");

    // #### Pan tool
	var mapPan = document.createElement("div");
	mapPan.setAttribute("id", "mapPan");
	mapPan.setAttribute("title", _mapPanInstructions);
	this.setButtonStyle_(mapPan);
	container.appendChild(mapPan);
	GEvent.addDomListener(mapPan, "click", function() {
	  select("mapPan");
	  if (_listener != null) {
	    GEvent.removeListener(_listener); // Remove marker functionality when pan is selected
	  }
	  if (_polygon != null) {
        _polygon.disableEditing();  // Remove polygon functionality when pan is selected
        if (_polygonClosed == false) {
            _map.clearOverlays();  // If the polygon hasn't been closed, remove it from the map.
        }
      }
      if (_mouseMoveListener != null){
        GEvent.removeListener(_mouseMoveListener); //remove mouse move listener if active
        _map.removeOverlay(_follow_marker); //Remove the marker
      }
    });
	
	// #### Point/Marker tool
	var mapMarkerTool = document.createElement("div");
	mapMarkerTool.setAttribute("id", "mapMarker");
	mapMarkerTool.setAttribute("title", _mapMarkerInstructions);
	this.setButtonStyle_(mapMarkerTool);
	container.appendChild(mapMarkerTool);
	var markerEventListener = GEvent.addDomListener(mapMarkerTool, "click", function() {
      if (_polygon != null) {
        _polygon.disableEditing(); // Remove polygon functionality when marker is selected
        if (_polygonClosed == false) {
            _map.clearOverlays();  // If the polygon hasn't been closed, remove it from the map.
        }
      }
	  CreateDraggableMarker();
	  select("mapMarker");
      placeMarker();
      _polygon = null;
    });
	
	// #### Polygon tool
	var mapPoly = document.createElement("div");
	mapPoly.setAttribute("id", "mapPoly");
	mapPoly.setAttribute("title", _mapPolyInstructions);
	this.setButtonStyle_(mapPoly);
	container.appendChild(mapPoly);
	var polyEventListener = GEvent.addDomListener(mapPoly, "click", function() {
	  select("mapPoly");
      if (_polygon != null) {
        _polygon.disableEditing(); // Remove old polygon functionality when polygon is selected
        if (_polygonClosed == false) {
            _map.clearOverlays();  // If the old polygon wasn't closed, remove it from the map.
        }
      }
	  if (_listener != null) {
	    GEvent.removeListener(_listener); // Remove marker functionality when polygon tool is selected
	  }
	  if(_mouseMoveListener != null){
        GEvent.removeListener(_mouseMoveListener); //remove mouse move listener if active
        _map.removeOverlay(_follow_marker); //Remove the marker
      }
      startShape();
    });
   
    // #### Extent tool
	_mapExtent = document.createElement("div");
	_mapExtent.setAttribute("id", "mapExtent");
	this.setButtonStyle_(_mapExtent);
	container.appendChild(_mapExtent);
    // Extent functionality is being set in Utilities.js (ExecuteZoomCheck).	

	_map.getContainer().appendChild(container);
	return container;
}

// Sets the proper CSS for the given button element.
MapToolControl.prototype.setButtonStyle_ = function(button) 
{
	if (button.id == "mapPan")
		{ button.style.backgroundImage = "url(images/button-map-drag-active.gif)"; 
		  button.style.left = "80px"; }
	else if (button.id == "mapMarker")
		{ button.style.backgroundImage = "url(images/button-map-pin.gif)";
		  button.style.left = "120px"; }
	else if (button.id == "mapPoly")
		{ button.style.backgroundImage = "url(images/button-map-polygon.gif)"; 
		  button.style.left = "160px"; }
	else if (button.id == "mapExtent")
		{ button.style.backgroundImage = "url(images/button-map-map-extent-disabled.gif)"; 
		  button.style.left = "200px"; }
	
	button.style.position = "absolute";
	button.style.top = "7px";
	button.style.width = "32px";
	button.style.height = "32px";
	button.style.cursor = "pointer";
	button.style.zindex = "3";
}
 
/// <summary>
/// When extent sqkm is greater than threshold status = false
/// When the status is false, disable the mapExtent map tool by removing the listener on it.
/// Otherwise, add the listener to back on the mapExtent tool.
/// </summary>
/// <returns>null</returns>
function ExtentToolStatus(status) 
{
    try
    {
        if(status == false) 
        {
            GEvent.clearInstanceListeners(_mapExtent);
            _mapExtent.style.cursor = "not-allowed";
            _mapExtent.style.backgroundImage = "url(images/button-map-map-extent-disabled.gif)";
            $("mapExtent").style.cursor = "not-allowed";
            $("mapExtent").title = "Zoom in to search by current extent";
            $("mapExtent").style.backgroundImage = "url(images/button-map-map-extent-disabled.gif)";
            _extentToolOn = false;  // For the pop-up bubble extent tool
        }
        else if(status == true && _extentToolOn == false) //RW - added check to see if tool was already on.
        {
            GEvent.addDomListener(_mapExtent, "click", function() {
                select("mapExtent");
               if (_polygon != null) 
               {
                 _polygon.disableEditing(); // Remove polygon functionality
               }
               try 
               {
                buildExtent();
               }
               catch(e)
               {
                //this is the end of the line for this error. The Method was called as an
                // event handler by Google API so this is as far as we call bubble the error.
                new ErrorAlert(e.message);
               }
            });
            _mapExtent.style.cursor = "pointer";
            _mapExtent.style.backgroundImage = "url(images/button-map-map-extent.gif)";
            $("mapExtent").style.cursor = "pointer";
            $("mapExtent").title = "Search by current extent";
            $("mapExtent").style.backgroundImage = "url(images/button-map-map-extent.gif)";
            _extentToolOn = true; // For the pop-up bubble extent tool
        }
        else if(status == true && _extentToolOn == true)
        {
            _mapExtent.style.cursor = "pointer";
            _mapExtent.style.backgroundImage = "url(images/button-map-map-extent.gif)";
            $("mapExtent").style.cursor = "pointer";
            $("mapExtent").title = "Search by current extent";
            $("mapExtent").style.backgroundImage = "url(images/button-map-map-extent.gif)";
        }
    }
    catch(e)
    {
        ErrorAlert(e.message);
    }
}

/// <summary>
/// Generates HTML string with map tools, based on mapExtent tool being enabled or disabled in pop-up bubble.
/// </summary>
/// <params name="placeName">The placeName to be displayed</params>
/// <params name="extentToolOn">bool.  Whether or not the extent search tool should be enabled or disabled.</params>
/// <returns>map tools as html content for pop-up bubble</returns>
function BubbleContent(placeName) {
    var extentTool = null; 
    if(_extentToolOn)
    {
        extentTool = "<td><div id='mapExtent' style='cursor:pointer;background-image:url(images/button-map-map-extent.gif)' title='Search by current extent' onclick='if(_extentToolOn){buildExtent();}'/></td>";
    }
    else
    {
        extentTool = "<td><div id='mapExtent' style='cursor:pointer;background-image:url(images/button-map-map-extent-disabled.gif)' title='Search by current extent' onclick='if(_extentToolOn){buildExtent();}'/></td>";    
    }
    
    var htmlcontent = "<span class='GreenBold'>" + placeName + "</span><br/>" +
                    "Refine your Area of Interest by dragging, searching again,<br/> or clicking another Find Place search result.<br/>" +
                    "<br /><span class='GreenBold'>Search the Image Catalog</span><br />" +
                    "To see available images in our Catalog, use one of these<br />" +
                    " tools.(Map Extent available only at certain zoom levels.)<br/>" +
                    "<table style='font-size:small;'>\n<tr>\n" +
                    "<td 'width:100px'><div id='mapMarker' style='cursor:pointer;background-image:url(images/button-map-pin.gif)' title='Place marker on map to search by point of interest' onclick='CreateDraggableMarker(),placeMarker()'/></td>\n" +
                    "<td 'width:100px'><div id='mapPoly' style='cursor:pointer;background-image:url(images/button-map-polygon.gif)' title='Draw polygon on map to search by area of interest' onclick='startShape();'/></td>\n" +
                    extentTool +
                    "</tr><tr>" +
                    "<td style='width:100px'><b>Point</b><br />" +
                    "Specific point</td>" +
                    "<td style='width:100px'><b>Polygon</b><br />" +
                    "Define an area</td>" +
                    "<td><b>Map Extent</b><br />" +
                    "Entire map window</td>" +
                    "</tr></table>";
    return htmlcontent;
}

/// <summary>
/// Places a marker on the map that follows the mouse around until the map is clicked.
/// </summary>
/// <returns>null</returns>
function CreateDraggableMarker()
{
	    //RW - Add a listener on map mouse move to show the icon moving with the mouse
       ClearEverything();
//	   var color = getColor(true);
	   //next, make map div cursor grab
	   // $("wrapper-map").style.cursor = "url(images/pointer.cur)"; //TODO: this doesn't work
	   	//next, add a marker.
      //var follow_marker = new GMarker(getLatLonFromPixel(320,105), {icon: getCustomIcon('images/red_marker_drag.gif'), clickable: false}); //Position of the Marker button
      _follow_marker = new GMarker(getLatLonFromPixel(320,105), {icon: getIcon(color), draggable: true});
      _map.addOverlay(_follow_marker);
	  _mouseMoveListener = GEvent.addDomListener(_map, "mousemove", function(latlng){
	  //Make a marker follow the mouse around the map.
	  var lat = latlng.lat();
	  var lng = latlng.lng();
	  _follow_marker.setLatLng(new GLatLng(lat, lng)); //any offset will have to be dependent on map zoom.
	  });
}
