//
// Copyright 2011 by Kelvin Thompson. All Rights Reserved.
//
// FILE: IsoLonLat.js
//
// REQIRES: mfutil.js
//          FOR: isPosInteger() isNumber()


var g_points = new Array();
var g_dataText = null;

var g_map1;
var g_map2;

function OPreset( center, l1, t1, l2 )
{
  this.center = center;
  this.l1 = l1;
  this.t1 = t1;
  this.l2 = l2;
}


function removePoint( point )
{
  var count = 0;
  for ( var i=0; i<g_points.length; i++ )
  {
    if ( g_points[i] != null )
    {
      if ( g_points[i].equals(point) )
        g_points[i] = null;
      else
        count++;
    }
  }
  
  // allow or disallow user setting of permalink
  allowPermaLink( count>0, null );

  updateDataText();
}

function addPoint( point )
{
  // see if there's already a null slot
  found = false;
  for ( var i=0; i<g_points.length; i++ )
  {
    if ( g_points[i] == null )
    {
      g_points[i] = point;
      found = true;  // use this empty slot
      break;
    }
  }

  // add a new slot of no empty ones found
  if ( ! found )
    g_points.push(point);

  // let user make a permalink
  allowPermaLink( true, null );
  
  updateDataText();
}


//=========================

var ua = navigator.userAgent.toLowerCase();

var linePosBias = {x:0,y:0};
if ( ua.indexOf('msie') != -1 )
{
  // tweak DIV position for IE
  linePosBias.x = +2;
  linePosBias.y =  0;
}
else if ( ua.indexOf('gecko/') != -1 )
{
  // tweak DIV position for Mozilla/Firefox
  linePosBias.x = +1;
  linePosBias.y =  0;
}
else if ( ua.indexOf('safari/') != -1 )
{
  // tweak DIV position for Safari
  linePosBias.x = +1;
  linePosBias.y =  0;
}


//=========================

// A HorizLine is an overlay that is a thin horizontal line
// implemented as a translucent DIV.
function HorizLine(ycoord, opt_weight, opt_color) {
  this.ycoord_ = ycoord;
  this.weight_ = opt_weight || 5;
  this.color_  = opt_color || "Blue";
}
HorizLine.prototype = new GOverlay();

// Creates the DIV representing this HorizLine.
HorizLine.prototype.initialize = function(map)
{
  // make a new, uninitialized DIV
  var div = document.createElement("div");

  // if no opacity, use IE6/IE7 workarounds
  if ( typeof div.style.opacity == "undefined"  &&
       navigator.appName == 'Microsoft Internet Explorer' )
  {
    // Dopey IE6/IE7 doesn't handle modern opacity.
    div.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=50)";
    
    // Create the DIV representing our HorizLine
    // IE6 won't accept a small DIV height unless we do this
    var txt = document.createTextNode("");
    div.appendChild(txt);
    div.style.fontSize = "1px";
    div.style.lineHeight = "0";
  }

  // set up positioning and 50% transparency
  div.style.position = "absolute";
  div.style.backgroundColor = this.color_;
  div.style.opacity = "0.5";  // ignored on IE6/IE7

  // Our HorizLine is flat against the map, so we add ourselves to the
  // MAP_PANE pane, which is at the same z-index as the map itself (i.e.,
  // below the marker shadows).
  map.getPane(G_MAP_MAP_PANE).appendChild(div);

  this.map_ = map;
  this.div_ = div;
}

// remove the main DIV from the map pane
HorizLine.prototype.remove = function()
{
  this.div_.parentNode.removeChild(this.div_);
}

// copy our data to a new HorizLine
HorizLine.prototype.copy = function()
{
  return new HorizLine(this.ycoord_, this.weight_, this.color_);
}

// redraw the HorizLine based on the current projection and zoom level
HorizLine.prototype.redraw = function(force)
{
  // We only need to redraw if the coordinate system has changed
  if (!force) return;

  // Calculate the DIV coordinates...
  var c1 = this.map_.fromLatLngToDivPixel( new GLatLng(this.ycoord_,0) );

  // Now position our DIV based on the DIV coordinates of our bounds
  this.div_.style.left   = -9999 + "px";
  this.div_.style.top    = (c1.y - this.weight_/2 + linePosBias.y) + "px";
  this.div_.style.height = this.weight_ + "px";
  this.div_.style.width  = 2*9999 + "px";
}


//=========================

// A VertLine is a simple overlay that <tbd>.
// It has a border of the given weight and color and can optionally
// have a semi-transparent background color.
function VertLine(xcoord, opt_weight, opt_color)
{
  this.xcoord_ = xcoord;
  this.weight_ = opt_weight || 5;
  this.color_  = opt_color || "Blue";
}
VertLine.prototype = new GOverlay();

// Creates the DIV representing this VertLine .
VertLine.prototype.initialize = HorizLine.prototype.initialize;

// Remove the main DIV from the map pane
VertLine.prototype.remove = HorizLine.prototype.remove;

// Copy our data to a new VertLine
VertLine.prototype.copy = function()
{
  return new VertLine(this.ycoord_, this.weight_, this.color_);
}

// Redraw the VertLine based on the current projection and zoom level
VertLine.prototype.redraw = function(force)
{
  // We only need to redraw if the coordinate system has changed
  if (!force) return;

  // Calculate the DIV coordinates...
  var c1 = this.map_.fromLatLngToDivPixel( new GLatLng(0,this.xcoord_) );

  // Now position our DIV based on the DIV coordinates of our bounds
  this.div_.style.left   = (c1.x - this.weight_/2 + linePosBias.x) + "px";
  this.div_.style.top    = -9999 + "px";
  this.div_.style.width  = this.weight_ + "px";
  this.div_.style.height = 2*9999 + "px";
}


//=========================


function showAgain( map )
{
  // wipe old overlays
  map.clearOverlays();
  
  // get map bounds
  var bounds = map.getBounds();
  var boundsMin = bounds.getSouthWest();
  var boundsMax = bounds.getNorthEast();
  var minX = boundsMin.lng();
  var minY = boundsMin.lat();
  var maxX = boundsMax.lng();
  var maxY = boundsMax.lat();
  
  if ( maxX<minX || bounds.isFullLng() )
  {
    minX = -180;
    maxX =  180;
  }

  // make new overlays
  for ( var i=0; i<g_points.length; i++ )
  {
    var gpt = g_points[i];
    if ( gpt != null )
    {
      // track if marker is in zone
      var markerFitsHoriz = false;
      var markerFitsVert = false;
 
      // see if we can add a horiz line for iso-latitude
      if ( minY < gpt.lat()  &&  gpt.lat() < maxY )
      {
        markerFitsHoriz = true;
        if ( map.useForm == null  ||  map.useForm.IsoLat.checked )
          map.addOverlay( new HorizLine(gpt.lat(),5,"Blue") );
      }
      
      // see if we can add a horiz line for anti-iso-latitude
      var negy = -gpt.lat();
      if ( minY < negy  &&  negy < maxY  &&  gpt.lat() != 0  &&
           (map.useForm == null  ||  map.useForm.AntiLat.checked) )
      {
        map.addOverlay( new HorizLine(negy,5,"Red") );
      }
 
      // see if we can add a vert line for iso-longitude
      if ( minX < gpt.lng()  &&  gpt.lng() < maxX )
      {
        markerFitsVert = true;
        if ( map.useForm == null  ||  map.useForm.IsoLon.checked )
        {
          map.addOverlay( new VertLine(gpt.lng(),5,"Blue") );
        }
      }
   
      // see if we can add a horiz line for anti-iso-longitude
      var opx = ((gpt.lng() + 360) % 360) - 180;
      if ( minX < opx  &&  opx < maxX  &&
          (map.useForm == null  ||  map.useForm.AntiLon.checked) )
      {
        map.addOverlay( new VertLine(opx,5,"Red") );
      }
 
      if ( markerFitsHoriz && markerFitsVert )
      {
        map.addOverlay( new GMarker(gpt) );
      }
    }
  }
}

function mapPairControls( mapA, mapB )
{
  var clickFunc = function(marker, point)
    {
      if (marker)
        removePoint(marker.getPoint());
      else if (point)
        addPoint(point);
      showAgain(mapA);
      showAgain(mapB);
    };
  
  GEvent.addListener( mapA, 'click', clickFunc );

  GEvent.addListener( mapB, 'moveend', function(){showAgain(mapB);} );

  GEvent.addListener( mapB, 'zoom', function(oldZoomLevel,newZoomLevel){showAgain(mapB);} );
}

function updateDataText()
{
  g_dataText = "";
  for ( var i=0; i<g_points.length; i++ )
  {
    var gpt = g_points[i];
    if ( gpt != null )
    {
      if ( g_dataText.length > 0 )
      g_dataText += "\n";
      g_dataText += gpt.lat() + "," + gpt.lng() + ";";
    }
  }

  // remove the last newline
  if ( g_dataText.length > 1 )
    g_dataText.length = g_dataText.length - 1;

  document.getElementById("dataText").value = g_dataText;
}

function getCheckBoxState ( id )
{
  var chkState = document.getElementById(id).checked;
  return chkState ? "1" : "0";
}

function makeXMLForMap(num,mapObj)
{
  var txt = "<map num='" + num + "' ";
  
  var centerLatLng = mapObj.getCenter();
  txt += "lat='" + centerLatLng.lat() + "' lng='" + centerLatLng.lng() + "' ";
  
  txt += "zoom='" + mapObj.getZoom() + "' ";
  
  var mapTypeName = mapObj.getCurrentMapType().getName(false);
  if ( mapTypeName == G_NORMAL_MAP.getName(false) )
    mapTypeName = "normal";
  else if ( mapTypeName == G_SATELLITE_MAP.getName(false) )
    mapTypeName = "satellite";
  else if ( mapTypeName == G_HYBRID_MAP.getName(false) )
    mapTypeName = "hybrid";
  else if ( mapTypeName == G_PHYSICAL_MAP.getName(false) )
    mapTypeName = "physical";
  else
    mapTypeName = "normal";

  txt += "type='" + mapTypeName + "' ";

  var enabled = getCheckBoxState( "m" + num + "ila" );
  enabled    += getCheckBoxState( "m" + num + "ilo" );
  enabled    += getCheckBoxState( "m" + num + "ala" );
  enabled    += getCheckBoxState( "m" + num + "alo" );
  txt += "en='" + enabled + "' />\n";
  
  return txt;
}

function makeXML()
{
  var xmlText = "<save>\n<coords>\n";

  for ( var i=0; i<g_points.length; i++ )
  {
    var gpt = g_points[i];
    if ( gpt != null )
      xmlText += "<coord lat='" + gpt.lat() + "' lng='" + gpt.lng() + "' />\n";
  }

  xmlText += "</coords>\n";

  xmlText += "<maps>\n";
  xmlText += makeXMLForMap(1,g_map1);
  xmlText += makeXMLForMap(2,g_map2);
  xmlText += "</maps>\n";
  
  xmlText += "</save>";

  return xmlText;
}


var g_regexpMatchWhitespace = /\s+/gm;

function updateMarkersFromDataText()
{
    g_points = new Array();

    // get textarea data and clear whitespace from string
    var textAreaStr = document.getElementById("dataText").value;
    var workStr = textAreaStr.replace( g_regexpMatchWhitespace,  "" );
    
    if ( workStr.length >= 3 )
    {
      // subdivide whole string by ";"
      var markerArray = workStr.split(";");
      if ( markerArray.length > 0 )
      {
          // subdivide each marker string string by ","
          for ( var i=0; i<markerArray.length; i++ )
          {
            var ptStr = markerArray[i];
            if ( ptStr.length >2)
            {
              var coordStr = ptStr.split(",");
              if ( coordStr.length == 2 )
              {
                 var lat = parseFloat(coordStr[0]);
                 var lng = parseFloat(coordStr[1]);
                 // tbd: ZZZ check ranges
                 g_points.push(new GLatLng(lat,lng));
              }
            }
          }
      }
    }

    // center maps at first and second marker positions
    if ( g_points.length > 0 )
    g_map1.setCenter( g_points[0] );
    if ( g_points.length > 1 )
    g_map2.setCenter( g_points[1] );

    showAgain(g_map1);
    showAgain(g_map2);
    updateDataText();
    
    allowPermaLink( true, null );
}


function clearAllFunc()
{
  g_points = new Array();
  g_map1.clearOverlays();
  g_map2.clearOverlays();
  g_dataTextElem.value = "";
  allowPermaLink( false, null );
}

function allowPermaLink ( allowClick, newURL )
{
  if ( g_points.length <= 0 )
  {
    allowClick = false;
    newURL     = null;
  }

  document.getElementById("persistButton").disabled = !allowClick;
  var msgElem  = document.getElementById("URLempty");
  var linkElem = document.getElementById("permURL");
  
  if ( (typeof newURL) != "string" )
  {
    linkElem.style.display        = "none";
    msgElem.firstChild.nodeValue  = "(not requested yet)";
    msgElem.style.display         = "inline";
  }
  else if ( newURL == "WAIT" )
  {
    linkElem.style.display        = "none";
    msgElem.firstChild.nodeValue  = "...request for URL in progress...";
    msgElem.style.display         = "inline";
  }
  else
  {
    msgElem.style.display         = "none";
    linkElem.href                 = newURL;
    linkElem.firstChild.nodeValue = newURL;
    linkElem.style.display        = "inline";
  }
}

//=============================================================================//

mfum_phpURL = "isoll_make.php";

mfum_makeXML = makeXML;

mfum_urlCallback = function ( newURL )
{
  allowPermaLink( false, newURL );
}
  
mfum_abortCallback = function ( )
{
  allowPermaLink( true, null );  
  alert( "Unfortunately, the server is not able to generate permanent " +
         "URLs at this time. Please try again later." );
}

function handleMakeURL ( )
{
  allowPermaLink( false, "WAIT" );
  mfum_requestURL();
}

//=============================================================================//

mfuf_phpURL = "isoll_get.php";

// set checkbox with 'id' to on/off state
// based on one-digit string 'stateChar' - "0" or "1"
function setCheckBoxState ( id, stateChar )
{
  var state = stateChar=="0" ? false : true; 
  document.getElementById(id).checked = state;
}

function mfuf_parseXMLNode ( xmlNode )
{
  var coordElem = xmlNode.documentElement.getElementsByTagName("coord");
  if ( coordElem.length < 1 )
  {
    alert( "Unfortunately, an error occurred attempting to retrieve the saved map." );
    return;
  }

  clearAllFunc();

  var added = false;
  for ( var i=0; i<coordElem.length; i++ )
  {
    var latStr = coordElem[i].getAttribute("lat");
    var lngStr = coordElem[i].getAttribute("lng");
    if ( isNumber(latStr) && isNumber(lngStr) )
    {
      addPoint( new GLatLng(parseFloat(latStr),parseFloat(lngStr)) );
      added = true;
    }
  }

  var mapElem = xmlNode.documentElement.getElementsByTagName("map");
  for ( var i=0; i<mapElem.length; i++ )
  {
    var numStr = mapElem[i].getAttribute("num");
    var numVal = parseInt(numStr);
    var latStr = mapElem[i].getAttribute("lat");
    var lngStr = mapElem[i].getAttribute("lng");
    if ( 1<=numVal && numVal<=2 && isNumber(latStr) && isNumber(lngStr) )
    {
      // derive zoom (or set to null)
      var zoom = mapElem[i].getAttribute("zoom");
      if ( !isPosInteger(zoom) )
        zoom = null;
      else
        zoom = parseInt(zoom);
      
      // derive map type (or set to null)
      var type = null;
      var typeName = mapElem[i].getAttribute("type");
      if ( typeof typeName == "string" )
      {
        switch ( typeName )
        {
        case "normal":     type = G_NORMAL_MAP;     break;
        case "satellite":  type = G_SATELLITE_MAP;  break;
        case "hybrid":     type = G_HYBRID_MAP;     break;
        case "physical":   type = G_PHYSICAL_MAP;   break;
        }
      }
      
      // derive iso-line settings
      var isoStr = mapElem[i].getAttribute("en");
      if ( typeof isoStr == "string" )
      {
        setCheckBoxState( "m"+numStr+"ila", isoStr.charAt(0) );
        setCheckBoxState( "m"+numStr+"ilo", isoStr.charAt(1) );
        setCheckBoxState( "m"+numStr+"ala", isoStr.charAt(2) );
        setCheckBoxState( "m"+numStr+"alo", isoStr.charAt(3) );
      }
      
      // set the map center, zoom and type
      var mapObj = eval("g_map"+numStr);
      var center = new GLatLng( parseFloat(latStr), parseFloat(lngStr) );
      mapObj.setCenter( center, zoom, type );
    }
  }

  if ( added )
  {
    allowPermaLink( false, null );
    showAgain(g_map1);
    showAgain(g_map2);
    updateDataText();
  }
}
  
var g_queryString = null;

mfuf_abortCallback = function ( )
{
  allowPermaLink( true, null );  
  alert( "The URL for this page contains the query string \"?" + g_queryString + "\". " +
         "This is a request for a saved map.\n\n" +
         "Unfortunately, your browser can't retrieve the saved map because the " +
         "MAPfrappe server is nonresponsive. Please try again later." );
}

function evaluateURLParams ( )
{
  var qmarkIdx = location.href.indexOf( '?' );
  if ( qmarkIdx > 7 )
  {
    var urlParams = location.href.slice( qmarkIdx+1 );
    var eqIdx     = urlParams.indexOf( '=' );
    var paramName = urlParams.substring( 0, eqIdx );
    var paramVal  = urlParams.slice( eqIdx+1 );
    g_queryString = urlParams;
    if ( paramName.toLowerCase()=="show" && isPosInteger(paramVal) )
      mfuf_fetchURL( paramVal );
  }
}

//=============================================================================//

function handleCompletedSearch ( mapNum, searchObj )
{
  var map = (mapNum==1) ? g_map1 : g_map2;
  var sw = new GLatLng( searchObj.resultViewport.sw.lat, searchObj.resultViewport.sw.lng );
  var ne = new GLatLng( searchObj.resultViewport.ne.lat, searchObj.resultViewport.ne.lng );
  var bounds = new GLatLngBounds( sw, ne );
  var zoom = map.getBoundsZoomLevel( bounds );
  map.setCenter(bounds.getCenter(), zoom);
  searchObj.results.length = 0;
}

function gmapSetup()
{
  g_dataTextElem = document.getElementById("dataText");
  g_dataTextElem.value = "";
  
  if ( ! GBrowserIsCompatible() )
    return;
  
  var adOpts =  // GGoogleBarAdsOptions
  {
    client : 'pub-2965340737172725'
  };
  var barOpts1 = { resultList: G_GOOGLEBAR_RESULT_LIST_SUPPRESS,
                   onSearchCompleteCallback: function(ob){handleCompletedSearch(1,ob);},
                   suppressInitialResultSelection: true,
                   adsOptions: adOpts
                 };
  var barOpts2 = { resultList: G_GOOGLEBAR_RESULT_LIST_SUPPRESS,
                   onSearchCompleteCallback: function(ob){handleCompletedSearch(2,ob);},
                   suppressInitialResultSelection: true,
                   adsOptions: adOpts
                 };
  
  scalePosition = new GControlPosition( G_ANCHOR_BOTTOM_LEFT, new GSize(3,36) ); 

  g_map1 = new GMap2(document.getElementById("map1div"), {googleBarOptions:barOpts1, draggableCursor:'crosshair'});
  g_map1.setCenter(new GLatLng(37.93,-92.90), 4);
  g_map1.addControl(new GScaleControl(), scalePosition);
  g_map1.enableGoogleBar();
  var mapUI = g_map1.getDefaultUI();
  mapUI.maptypes = {normal:true, satellite:true, hybrid:true, physical:true};
  g_map1.setUI(mapUI);
  g_map1.disableScrollWheelZoom();
  g_map1.useForm = document.M1CheckBoxes;

  g_map2 = new GMap2(document.getElementById("map2div"), {googleBarOptions:barOpts2, draggableCursor:'crosshair'});
  g_map2.setCenter(new GLatLng(37.93,-92.90), 4);
  g_map2.addControl(new GScaleControl(), scalePosition);
  g_map2.enableGoogleBar();
  var mapUI = g_map2.getDefaultUI();
  mapUI.maptypes = {normal:true, satellite:true, hybrid:true, physical:true};
  g_map2.setUI(mapUI);
  g_map2.disableScrollWheelZoom();
  g_map2.useForm = document.M2CheckBoxes;

  mapPairControls(g_map1,g_map2);
  mapPairControls(g_map2,g_map1);

  // monitor the window resize event and let the map know when it occurs
  if (window.attachEvent)
    window.attachEvent("onresize", function() {g_map1.checkResize();g_map2.checkResize();} );
  else
    window.addEventListener("resize", function() {g_map1.checkResize();g_map2.checkResize();}, false);

  scrubExampleList();

  evaluateURLParams();
}

