//
// Copyright 2011 by Kelvin Thompson. All Rights Reserved.
//
// FILE: index.js
//
// REQIRES: mfutil.js
//

// GMap2() objects - set once in gmapSetup()
var g_map1;
var g_map2;

// references to HTML elements - set once in gmapSetup() - status readout
var g_statusSpan = null;  // document.getElementById("EditStatus");
var g_statusText = null;  // g_statusSpan.firstChild;

// references to HTML elements - set once in gmapSetup() - buttons
var g_buttClose  = null;   // document.getElementById("ctrlCloseOutline");
var g_buttEnd    = null;   // document.getElementById("ctrlEndOutline");
var g_buttClear  = null;   // document.getElementById("ctrlClear");
var g_buttDelete = null;   // document.getElementById("ctrlDeleteLast");

var g_polylineArray = new mfOrderedArray(); // array of 'mfPolyline' objects

var g_inEdit = false;              // 'true' when user is editing
var g_lastStartMarker = null;      // start marker

// Google's "tiny" marker icon
var g_tiny_icon = new GIcon();
g_tiny_icon.image = "http://www.google.com/mapfiles/dd-start.png";
g_tiny_icon.shadow = "http://www.google.com/mapfiles/shadow50.png";
g_tiny_icon.iconSize = new GSize(12,20);
g_tiny_icon.shadowSize = new GSize(22,20);
g_tiny_icon.iconAnchor = new GPoint(6,20);
g_tiny_icon.infoWindowAnchor = new GPoint(5,1);

g_isIE6 = false;

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

function mfPolyline ( )
{
  // attributes
  this.closed   = false;        // possibly set TRUE later in this.finish()
  this.vtxArray = new mfOrderedArray();  // array of GLatLng() objects
  this.polyline = null;         // GPolyline() object
  this.distance = 0;            // summed length of all segments, in meters
  this.area     = 0;            // area of closed polyline, in sq meters
}

mfPolyline.prototype.getVtxArray = function ( )
{
  return this.vtxArray ? this.vtxArray.getArray() : null;
}

mfPolyline.prototype.getVtxCount = function ( )
{
  return this.vtxArray ? this.vtxArray.getCount() : 0;
}

mfPolyline.prototype.getDistance = function ( )
{
  return this.distance;
}

mfPolyline.prototype.getArea = function ( )
{
  return this.area;
}

mfPolyline.prototype.updateMap1GPolyline = function ( )
{
  // remove existing overlay
  if ( this.polyline != null )
    g_map1.removeOverlay( this.polyline );

  // update GPolyline object and display on map
  this.polyline  = new GPolyline( this.vtxArray.getArray() );
  g_map1.addOverlay( this.polyline );
}

mfPolyline.prototype.updateStartMarker = function ( show )
{
  // remove any lingering "start" marker
  if ( g_lastStartMarker != null )
      g_map1.removeOverlay( g_lastStartMarker );

  if ( show && !this.closed )
  {
    g_lastStartMarker = new GMarker( this.vtxArray.getElement(0), g_tiny_icon );
    g_map1.addOverlay( g_lastStartMarker );
  }
}

mfPolyline.prototype.addPoint = function ( point )
{
  this.vtxArray.push( point );
  this.updateMap1GPolyline();
  this.distance = this.polyline.getLength();  // meters

  if ( this.vtxArray.getCount() == 1 )
    this.updateStartMarker( true );
}

mfPolyline.prototype.deleteLastPoint = function ( )
{
  this.vtxArray.deleteLast();
  this.updateMap1GPolyline();
  this.distance = this.polyline.getLength();  // meters
  
  if ( this.closed )
  {
    this.closed = false;
    this.area = 0;
    this.updateStartMarker( true );
  }
}

mfPolyline.prototype.finish = function ( close )
{
  // remove any lingering "start" marker
  this.updateStartMarker( false );

  if ( close  &&  this.vtxArray.getCount() >= 3 )
  {
    // BEFORE closing the outline - ask Google to compute area of polygon
    var gmPolygon = new GPolygon( this.vtxArray.getArray() );
    this.area = gmPolygon.getArea();  // square meters

    // add final point to closed polyline
    this.vtxArray.push( this.vtxArray.getElement(0) );
    this.closed = true;
    
    this.updateMap1GPolyline();

    // ask Google to compute length of polyline
    this.distance = this.polyline.getLength();  // meters
  }
}

mfPolyline.prototype.destroy = function ( )
{
  // remove any lingering "start" marker
  this.updateStartMarker( false );
  
  var userPoints = this.vtxArray.getCount();
  this.vtxArray = null;
  this.polyline = null;

  if ( userPoints > 0 )
  {
    showMetrics();
    remakeOffsetPolylines( g_map2 );
  }
}

mfPolyline.prototype.initFromXMLElem  = function ( xmlElem )
{
  var vtxElements = xmlElem.getElementsByTagName("vtx");
  if ( vtxElements.length < 2 )
    return "BAD";

  this.vtxArray = new mfOrderedArray();

  for ( var i=0; i<vtxElements.length; i++ )
  {
    var latStr = vtxElements[i].getAttribute("lat");
    var lngStr = vtxElements[i].getAttribute("lng");
    if ( isNumber(latStr) && isNumber(lngStr) )
    {
      this.vtxArray.push( new GLatLng(parseFloat(latStr),parseFloat(lngStr)) );
    }
  }

  var topoStr = xmlElem.getAttribute("topo");
  this.closed = (topoStr == "1");

  if ( this.closed )
  {
    // Build a GPolygon from the vertices (before cloning first-to-last)
    // and get the area polygon area.
    var gmPolygon = new GPolygon( this.vtxArray.getArray() );
    this.area = gmPolygon.getArea();  // square meters

    // clone the first vert to the end to make a closed loop
    this.vtxArray.push( this.vtxArray.getElement(0) );
  }

  this.updateMap1GPolyline();
  this.distance = this.polyline.getLength();  // meters

  return "";
}

mfPolyline.prototype.makeXML = function ( )
{
  if ( this.vtxArray.getCount() <= 1 )
    return "";

  var isClosed = this.closed ? 1 : 0;
  var xmlText = "<polyline topo='" + isClosed + "'>\n";

  // Loop thru points in this point array. Skip the last point
  // if this is a closed polyline.
  var numPts = this.vtxArray.getCount() - isClosed;
  for ( var i=0; i<numPts; i++ )
  {
    var gpt = this.vtxArray.getElement(i);
    xmlText += "<vtx lat='" + gpt.lat() + "' lng='" + gpt.lng() + "' />\n";
  }

  xmlText += "</polyline>\n";
  return xmlText;
}

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

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 + "' />\n";

  return txt;
}

function makeXML ( )
{
  var xmlText = "<save>\n<polylines>\n";
  
  var numOutlines = g_polylineArray.getCount();
  for ( var i=0; i<numOutlines; i++ )
    xmlText += g_polylineArray.getElement(i).makeXML();

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

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

  xmlText += "</save>";

  return xmlText;
}

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

function addPolyPoint( point )
{
  // see if we're starting a new polyline
  if ( ! g_inEdit )
  {
    // start a new partial polyline at the end of 'g_polylineArray'
    g_polylineArray.push( new mfPolyline() );
    g_inEdit = true;
  }

  // append point to in-progress polyline
  var lastOutline = g_polylineArray.getLast();
  lastOutline.addPoint( point );

  updateGUIAfterEdit();
  remakeOffsetPolylines( g_map2 );
  
  if ( g_polylineArray.getCount() > 1  ||  lastOutline.getVtxCount() > 1 )
    allowPermaLink( true, null );
}

// Event handler for "Close Outline" and "End Outline" buttons.
// Finish the polyline we're currently editing. The 'closed'
// parameter determines whether we add a final point matching the
// first point.
function handleFinishPolyline( closed )
{
  // quit if we're not even editing a polyline
  if ( ! g_inEdit )
    return;

  var lastPolylineObj = g_polylineArray.getLast();

  if ( lastPolylineObj.getVtxCount() < 2 )
  {
    // polyline had just one point - kill the whole polyline
    lastPolylineObj.destroy();
    g_polylineArray.deleteLast();
  }
  else
  {
    lastPolylineObj.finish( closed );
  }

  g_inEdit = false;
  updateGUIAfterEdit();
  remakeOffsetPolylines( g_map2 );
}

function clearAllPolylines()
{
  g_map1.clearOverlays();
  g_polylineArray = new mfOrderedArray();
  g_inEdit = false;
  remakeOffsetPolylines(g_map2);
  updateGUIAfterEdit();
  allowPermaLink( false, null );
}

function handleClearButton()
{
  clearAllPolylines();
}

function handleDeleteButton()
{
  var lastOutline = g_polylineArray.getLast();
  if ( ! lastOutline )
    return;
  
  // get number of verts in last outline
  var vtxCount = lastOutline.getVtxCount();
  if ( vtxCount <= 1 )
  {
    // only one vertex - kill the whole outline
    lastOutline.destroy();
    g_polylineArray.deleteLast();
    g_inEdit = false;
  }
  else
  {
    // delete last point in outline
    lastOutline.deleteLastPoint();
    
    // put this outline in edit mode
    if ( ! g_inEdit )
    {
      lastOutline.updateStartMarker( true );
      g_inEdit = true;
    }
  }

  remakeOffsetPolylines(g_map2);
  updateGUIAfterEdit();

  var numOutlines = g_polylineArray.getCount();
  if ( numOutlines < 1 )
    allowPermaLink( false, null );
  else if ( numOutlines == 1  &&  g_polylineArray.getLast().getVtxCount() <= 1 )
    allowPermaLink( false, null );
}

function remakeOffsetPolylines( map )
{
  // loop thru list of mfPolyline objects - find bounds of all points
  var bounds = new GLatLngBounds();
  var numOutlines = g_polylineArray.getCount();
  for ( var i=0; i<numOutlines; i++ )
  {
    // get point array from this mfPolyline object
    var thisPtArray = g_polylineArray.getElement(i).getVtxArray();
    if ( thisPtArray != null )
    {
      // loop thru points in this point array
      var vtxCount = g_polylineArray.getElement(i).getVtxCount();
      for ( var j=0; j<vtxCount; j++ )
      {
        var thisPt = thisPtArray[j];
        if ( thisPt != null )
          bounds.extend( thisPt );
      }
    }
  }
    
  // get center of computed bounds
  var boundsCenter = bounds.getCenter();

  // compute comparison map center
  var cx = map.getCenter().lng();
  var cy = map.getCenter().lat();

  // for making new point arrays
  var shiftedPtArray = new Array();

  // wipe old overlays
  map.clearOverlays();

  // make new overlays
  for ( var i=0; i<numOutlines; i++ )
  {
    var thisPtArray = g_polylineArray.getElement(i).getVtxArray();
    if ( thisPtArray != null )
    {
      shiftedPtArray.length = 0;

      // loop thru points in this point array
      var vtxCount = g_polylineArray.getElement(i).getVtxCount();
      for ( var j=0; j<vtxCount; j++ )
      {
        var gpt = thisPtArray[j];
        if ( gpt != null )
        {
          // get offset of reference point from center
          var ref_dx = gpt.lng() - boundsCenter.lng();
          var ref_dy = gpt.lat() - boundsCenter.lat();

          // latitude radii at reference & comparison points
          var ref_latR = Math.cos( gpt.lat() * (Math.PI/180) );
          var cmp_latR = Math.cos( (cy+ref_dy) * (Math.PI/180) );
 
          // adjust X for latitude circumference difference
          var cmp_x = cx + (ref_dx * ref_latR / cmp_latR);
  
          shiftedPtArray.push( new GLatLng(cy+ref_dy,cmp_x) );
        }
      }

      map.addOverlay( new GPolyline(shiftedPtArray) );
    }
  }
}

function handleMapClick ( overlay, point )
{
  if ( point )
  {
    addPolyPoint(point);
    updateGUIAfterEdit();
  }
}

function handleMapResize()
{
  g_map1.checkResize();
  g_map2.checkResize();
  remakeOffsetPolylines(g_map2);
}

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

var g_outlineControl = null;

function OutlineControl( outlineDiv, offset )
{
  this.outlineDiv = outlineDiv;
  this.offset     = offset;
}

OutlineControl.prototype = new GControl();

OutlineControl.prototype.printable = function()
{
  return true;
}

OutlineControl.prototype.selectable = function()
{
  return false;
}

OutlineControl.prototype.initialize = function(map)
{
  outerDiv = map.getContainer();
  outerDiv.appendChild( this.outlineDiv );
  return this.outlineDiv;
}

OutlineControl.prototype.getDefaultPosition = function()
{
  return new GControlPosition( G_ANCHOR_TOP_LEFT, this.offset );
}

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

function handleMoveStart()
{
  // if we don't have an outline, bail out
  if ( g_polylineArray.getCount() <= 0 )
    return;
    
  // if first outline has just one point, bail out
  if ( g_polylineArray.getElement(0).getVtxCount() <= 1 )
    return;

  // get my site's top-level DIV containing map#2 (comparison map)
  var myMapDiv = document.getElementById("map2div");

  // The first child of 'myMapDiv' appears to be a generic
  // container for the whole moveable map surface - i.e. the
  // content that moves underneath the map controls. Make sure
  // this DIV exists and has style settings.
  var gmContainerDiv = myMapDiv.firstChild;
  if ( gmContainerDiv == null       ||
       gmContainerDiv.style == null )
    return;

  // confirm that map-container's style looks legit
  var style = gmContainerDiv.style;
  if ( style.position != "absolute" ||
       style.left     != "0px"      ||
       style.top      != "0px"      )
    return;

  // The only child of 'gmContainerDiv' appears to overlay/contain
  // the whole map and establish overall map translation (plus cursor).
  // Make sure this DIV exists and has style settings.
  var gmTranslateDiv = gmContainerDiv.firstChild;
  if ( gmTranslateDiv == null       ||
       gmTranslateDiv.style == null )
    return;

  // confirm that the style of the translation DIV looks legit
  var gmTranslateStyle = gmTranslateDiv.style;
  if ( gmTranslateStyle.position != "absolute"   ||
       gmTranslateStyle.zIndex   != "0"          )
    return;

  // The "left" and "top" style properties of 'gmTranslateDiv' say how
  // much the whole map is translated. Later on, when we "latch" the
  // user's outline up to the controls layer, we will need to know this
  // translation - so record it in a GSize object.
  // NOTE: 'style.left' is in a form like "123px", but we need to pass
  // an actual number to the constructor for GSize - so use parseInt().
  var outlineOffset = new GSize(
    parseInt(gmTranslateStyle.left), parseInt(gmTranslateStyle.top) );

  // 'gmTranslateDiv' contains several children that together make up the
  // moveable map. Loop thru the children and find the one with "zIndex==101".
  var node;
  for ( node=gmTranslateDiv.firstChild; node!=null; node=node.nextSibling )
  {
    // quit if we find a child that's not a DIV or doesn't have style settings
    if ( node.nodeType != 1                   ||   //Node.ELEMENT_NODE==1
         node.nodeName.toLowerCase() != "div" ||
         node.style == null                   )
      return;
    
    // break out of the loop when we find the right zIndex
    if ( node.style.zIndex == 101 )
      break;
  }

  // quit the function if the loop failed
  if ( node == null  ||  node.style.zIndex != 101  )
    return;

  // the DIV we found in the loop contains the user's outline
  var userOutlineDiv = node;

  // Now confirm that 'userOutlineDiv' really looks like it contains
  // an outline element.
  var outlineGraphics = userOutlineDiv.firstChild;
  if ( outlineGraphics == null        ||
       outlineGraphics.style == null  ||
       outlineGraphics.nodeType != 1  )
    return;

  // Outline element should either be an IMG (Safari 2), an SVG (Firefox),
  // a SHAPE (IE), or a CANVAS (Safari 3, Chrome). If not, quit the function.
  var outlineElemType = outlineGraphics.nodeName.toLowerCase();
  if ( outlineElemType != "img"    &&
       outlineElemType != "svg"    &&
       outlineElemType != "shape"  &&
       outlineElemType != "canvas" )
    return;

  // clone the DIV that contains graphics for the outline
  var cloneDiv = userOutlineDiv.cloneNode(true);
  cloneDiv.id = "kktovr";

  // Stupid IE6/IE7 doesn't properly clone the SHAPE element.
  // It appears that copying outerHTML from the SHAPE element
  // accomplishes what we want.
  if ( cloneDiv.runtimeStyle != null  &&  outlineElemType == "shape" )
  {
    var origShapeCount  = userOutlineDiv.childNodes.length;
    var cloneShapeCount = cloneDiv.childNodes.length;
    var loopCount       = Math.max( origShapeCount, cloneShapeCount );
    for ( var i=0; i<loopCount; i++ )
    {
      var origElem  = userOutlineDiv.childNodes[i];
      var cloneElem = cloneDiv.childNodes[i];
      if ( isElemType(origElem,"shape")  &&  isElemType(cloneElem,"shape") )
      {
        cloneElem.outerHTML = origElem.outerHTML;
      }
    }
  }
  else if ( outlineElemType == "canvas" )
  {
    var origCount  = userOutlineDiv.childNodes.length;
    var cloneCount = cloneDiv.childNodes.length;
    var loopCount  = Math.max( origCount, cloneCount );
    for ( var i=0; i<loopCount; i++ )
    {
      var origElem  = userOutlineDiv.childNodes[i];
      var cloneElem = cloneDiv.childNodes[i];
      if ( isElemType(origElem,"canvas")  &&  isElemType(cloneElem,"canvas") )
      {
        var cloneCtx = cloneElem.getContext("2d");
        cloneCtx.globalAlpha = "1.0";
        cloneCtx.drawImage( origElem, 0, 0 );
      }
    }
  }

  // wipe existing map overlays in preparation for user action
  g_map2.clearOverlays();

  // Add the cloned elements as a control for the map. We will remove
  // this control and recompute the stuck-to-map overlay once the user
  // finishes moving the map.
  g_outlineControl = new OutlineControl( cloneDiv, outlineOffset );
  g_map2.addControl( g_outlineControl );
}

function handleMoveEnd()
{
  // remove control - we only use it as long as the user is moving the map
  if ( g_outlineControl )
    g_map2.removeControl( g_outlineControl );

  g_outlineControl = null;
  remakeOffsetPolylines( g_map2 );
  allowPermaLink( true, null );
}

function handleZoom(oldZoomLevel,newZoomLevel)
{
  remakeOffsetPolylines( g_map2 );
  allowPermaLink( true, null );
}

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

mfum_phpURL = "mover_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(); // calls makeXML() or mfum_abortCallback()
}

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

function updateEditStatusText()
{
  if ( g_inEdit )
  {
    g_statusSpan.className = "editActive";
    g_statusText.nodeValue = "MAP - click to enter next point";
  }
  else
  {
    g_statusSpan.className = "editActive";
    g_statusText.nodeValue = "MAP - click to enter first point";
  }

  if ( ! g_inEdit )
  {
    if ( g_lastStartMarker != null )
    {
      g_map1.removeOverlay(g_lastStartMarker);
      g_lastStartMarker = null;
    }
  }
}

function showMetrics ( )
{
  if ( g_isIE6 )
    return;
  
  var sumLength = 0;
  var sumArea   = 0;

  for ( var i=0; i<g_polylineArray.getCount(); i++ )
  {
    var polylineObj = g_polylineArray.getElement(i);
    sumLength += polylineObj.getDistance();
    sumArea   += polylineObj.getArea();
  }
    
  var pElem = document.getElementById("measurements");

  if ( sumLength <= 0  &&  sumArea <= 0 )
  {
    pElem.style.visibility = "hidden";
  }
  else
  {
    var lengthTxt;
    if ( sumLength <= 0 )
      lengthTxt = "n/a";
    else if ( sumLength < 10000 )
      lengthTxt = sumLength.toPrecision(4) + " meters";
    else if ( sumLength < 1e9 )
      lengthTxt = (sumLength*1e-3).toFixed(0) + " km";
    else
      lengthTxt = (sumLength*1e-3).toPrecision(4) + " km";

    var areaTxt;
    if ( sumArea <= 0 )
      areaTxt = "n/a";
    else if ( sumArea < 10000 )
      areaTxt = sumArea.toPrecision(4) + " sq meters";
    else if ( sumArea < 200000 )
      areaTxt = sumArea.toFixed(0) + " sq meters";
    else if ( sumArea < 1e9 )
      areaTxt = (sumArea*(1e-6)).toPrecision(4) + " sq km";
    else if ( sumArea < 1e12 )
      areaTxt = (sumArea*(1e-6)).toFixed(0) + " sq km";
    else
      areaTxt = (sumArea*(1e-6)).toPrecision(4) + " sq km";

    document.getElementById("lengthReadout").firstChild.nodeValue = lengthTxt;
    document.getElementById("areaReadout").firstChild.nodeValue   = areaTxt;

    pElem.style.visibility = "visible";
  }
}

function allowPermaLink ( allowClick, newURL )
{
  if ( g_polylineArray.getCount() <= 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";
  }
}

function updateGUIAfterEdit()
{
  updateEditStatusText();
  showMetrics();
}

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

mfuf_phpURL = "mover_get.php";

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

  for ( var i=0; i<polylineElements.length; i++ )
  {
    var newPolylineObj = new mfPolyline();
    newPolylineObj.initFromXMLElem( polylineElements[i] );
    g_map1.addOverlay( newPolylineObj.polyline );
    g_polylineArray.push( newPolylineObj );
  }

  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 = parseInt(zoom);
      else
        zoom = null;
      
      // 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;
        }
      }
      
      // 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 ( g_polylineArray.getCount() > 0 )
  {
    remakeOffsetPolylines( g_map2 );
    updateGUIAfterEdit();
  }
}

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()
{
  if ( ! GBrowserIsCompatible() )
    return;
  
  // determine IE6
  g_isIE6 = (navigator.userAgent.indexOf('MSIE 6.') != -1 );

  // GGoogleBarOptions
  var adOpts = {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_map2 = new GMap2( document.getElementById("map2div"), {googleBarOptions:barOpts2} );
  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_statusSpan = document.getElementById("EditStatus");
  g_statusText = g_statusSpan.firstChild;

  g_buttClose  = document.getElementById("ctrlCloseOutline");
  g_buttEnd    = document.getElementById("ctrlEndOutline");
  g_buttClear  = document.getElementById("ctrlClear");
  g_buttDelete = document.getElementById("ctrlDeleteLast");

  GEvent.addListener( g_map1, 'click',     handleMapClick  );
  GEvent.addListener( g_map2, 'movestart', handleMoveStart );
  GEvent.addListener( g_map2, 'moveend',   handleMoveEnd   );
  GEvent.addListener( g_map2, 'zoom',      handleZoom      );

  // Monitor the window resize event and let the map know when it occurs
  if ( window.attachEvent )
    window.attachEvent("onresize", handleMapResize );
  else
    window.addEventListener("resize", handleMapResize, false);

  scrubExampleList();

  evaluateURLParams();
}

