// index.js
// Copyright (C) 2008 University of California - San Diego

var objMap;        // Google Map object
var objLayers;     // My Layer Manager (tile layer manager)
var cached = [];   // array of cached GDownloadUrl documents.
var icons = [];    // Base icons "first" and "last"
var layers = [];   // array of objLayers added with objLayer.addLayer();

var objIndicator;  // Indicates where nearest click went.

Date.prototype.getAltimetryStamp = function() { 
  var yr = this.getUTCYear();
  var mo = this.getUTCMonth() + 1;
  var da = this.getUTCDate();
  var str = yr+''+mo+''+da;
  return str;
};


GMap2.prototype.addOverlays = function(a) { 
  for(var k in a) { 
    this.addOverlay(a[k]);
  }
  return true;
}

GMap2.prototype.removeOverlays = function(a) { 
  for(var k in a) { 
    this.removeOverlay(a[k]);
  }
  return true;
}


GMap2.prototype.addRimpacOpsArea = function() { 
  if( layers["rimpacOps"] ) { 
    if( !layers["rimpacOps"].visible ) { 
      objLayers.addLayer(layers["rimpacOps"]);
    }
    layers["rimpacOps"].visible = true;
    return true;
  }

  layers["rimpacOps"] = new SingleLayer('');
  layers["rimpacOps"].setHost("cordc.ucsd.edu");
  layers["rimpacOps"].setBaseUrl("/projects/rimpac/2008/tiles/opsArea");
  objLayers.addLayer(layers["rimpacOps"]);
  layers["rimpacOps"].visible = true;
}


GMap2.prototype.removeRimpacOpsArea = function() { 
  if( layers["rimpacOps"] && layers["rimpacOps"].visible ) { 
    objLayers.removeLayer(layers["rimpacOps"]);
    layers["rimpacOps"].visible = false;
  }
}



GMap2.prototype.addNrlNowcast = function() { 
  if( layers["nrlNowcast"] ) { 
    if( !layers["nrlNowcast"].visible ) { 
      this.addOverlay(layers["nrlNowcast"]);
    }
    layers["nrlNowcast"].visible = true;
    return true;
  }

  var url = "http://www7320.nrlssc.navy.mil/global_nlom32/navo/HAWUV_ZOOM.gif";
  var sw = new GLatLng(17.124128,-162.425136);
  var ne = new GLatLng(24.569304,-153.419386);

  layers["nrlNowcast"] = new GGroundOverlay(url,new GLatLngBounds(sw,ne));
  this.addOverlay(layers["nrlNowcast"]);
  layers["nrlNowcast"].visible = true;
}

GMap2.prototype.removeNrlNowcast = function() { 
  if( layers["nrlNowcast"] && layers["nrlNowcast"].visible ) { 
    this.removeOverlay(layers["nrlNowcast"]);
    layers["nrlNowcast"].visible = false;
  }
}


GMap2.prototype.centerAndZoomToPolygon = function(poly) { 
  var bb = poly.getBounds();
  this.setCenter(bb.getCenter());
  var zoom = Math.min(10,this.getBoundsZoomLevel(bb));
  this.setZoom(zoom);
}

GMap2.prototype.addStormTracks = function() { 
  if( !cached["listStorms"] ) { 
    alert("Cached listStorms not found -- listen for listStormsLoaded");
    return false;
  }

  if( layers["stormTracks"] && layers["stormTracks"].visible ) { 
    return true;
  }

  var dom = GXml.parse(cached["listStorms"]);
  var storms = dom.getElementsByTagName("storm");
  layers["stormTracks"] = [];
  // var points = [];
  var a_storm = get_url_parameter("sid");
  for(var i=0,n=storms.length;i<n;i++) { 
    layers["stormTracks"][i] = createStormPolyline(storms[i]);
    // points.push(createStormEndPoint(storms[i]));
    if( storms[i].getAttribute("id") == a_storm ) { 
      objMap.centerAndZoomToPolygon(layers["stormTracks"][i]);
    }
  }
  objMap.addOverlays(layers["stormTracks"]);
  layers["stormTracks"].visible = true;
}

GMap2.prototype.removeStormTracks = function() { 
  if( layers["stormTracks"] && layers["stormTracks"].visible ) { 
    objMap.removeOverlays(layers["stormTracks"]);
    layers["stormTracks"].visible = false;
  }
}



GMap2.prototype.addSoloFloats = function() { 
  if( !cached["listFloats"] ) { 
    alert("Cached listFloats not found -- listen for listFloatsLoaded");
    return false;
  }

  if( layers["soloFloats"] && layers["soloFloats"].visible ) { 
    return true;
  }

  var dom = GXml.parse(cached["listFloats"]);
  var floats = dom.getElementsByTagName("float");
  layers["soloFloats"] = [];
  layers["soloPoints"] = [];
  var a_float = get_url_parameter("id");
  for(var i=0,n=floats.length;i<n;i++) { 
    layers["soloFloats"][i] = createSoloPolyline(floats[i]);
    layers["soloPoints"].push(createSoloEndPoint(floats[i]));

    if( floats[i].getAttribute("id") == a_float ) { 
      objMap.centerAndZoomToPolygon(layers["soloFloats"][i]);
    }
  }

  objMap.addOverlays(layers["soloFloats"]);
  layers["soloFloats"].visible = true;

  objMap.addOverlays(layers["soloPoints"]);
  layers["soloPoints"].visible = true;
}


GMap2.prototype.removeSoloFloats = function() { 
  if( layers["soloFloats"] && layers["soloFloats"].visible ) { 
    objMap.removeOverlays(layers["soloFloats"]);
    layers["soloFloats"].visible = false;
  }
  if( layers["soloPoints"] && layers["soloPoints"].visible ) { 
    objMap.removeOverlays(layers["soloPoints"]);
    layers["soloPoints"].visible = false;
  }
}



GMap2.prototype.addLatestAltimetry = function() { 
  if( !cached["listAltimetry"] ) { 
    alert("Cached listAltimetry not found -- listen for listAltimetryLoaded");
    return false;
  }

  if( typeof(layers["altimetry"]) != "undefined" ) { 
    if( !layers["altimetry"].visible ) { 
      objLayers.addLayer(layers["altimetry"]);
    }
    layers["altimetry"].visible = true;
    return true;
  }

  var dom = GXml.parse(cached["listAltimetry"]);
  var stamps = dom.getElementsByTagName("stamp");
  var maxStamp = null;
  for(var i=0,n=stamps.length;i<n;i++) { 
    var stamp = stamps[i].firstChild.nodeValue;
    if( !maxStamp || stamp.toString() > maxStamp ) { 
      maxStamp = stamp.toString();
    }
  }
  if( !maxStamp ) { 
    return false;
  }
  layers["altimetry"] = new AltimetryLayer(maxStamp);
  layers["altimetry"].setOpacity(50);
  objLayers.addLayer(layers["altimetry"]);
  layers["altimetry"].visible = true;
}

GMap2.prototype.removeLatestAltimetry = function() { 
  if( layers["altimetry"] && layers["altimetry"].visible ) { 
    objLayers.removeLayer(layers["altimetry"]);
    layers["altimetry"].visible = false;
  }
}


function createStormEndPoint(stormEl) { 
  if( !stormEl ) { 
    return null;
  }
  // TODO
  return null;
}


function createStormPolyline(stormEl) { 
  if( !stormEl ) { 
    return null;
  }
  var track = [];
  var points = stormEl.getElementsByTagName("point");
  var keyed_points = [];
  var point_tss = [];

  for(var i=0,n=points.length; i<n; i++) { 
    if ( parseInt(points[i].getAttribute("for")) ) { 
      // skip forecasts
      continue;
    }

    var ts = parseInt(points[i].getAttribute("ts"));
    var lat = parseFloat(points[i].getAttribute("lat"));
    var lon = parseFloat(points[i].getAttribute("lon"));
    keyed_points[ts] = new GLatLng(lat,lon);
    point_tss.push(ts);
  }

  point_tss.sort(sort_numeric);
  for(var i=0,n=point_tss.length;i<n;i++) { 
    var ts = point_tss[i];
    track.push(keyed_points[ts]);
  }

  var Pauly = new GPolyline(track);
  Pauly.storm_id = stormEl.getAttribute("id");
  Pauly.point_tss = point_tss;

  GEvent.addListener(Pauly,"click",function(latlng) { 
    var V = getNearestVertex(Pauly,latlng);
    objIndicator.setLatLng(V);

    var html = '<div id="infoWindow">'+getStormInfoForVertex(Pauly,V)+"</div>";
    objMap.openInfoWindowHtml(V,html,{maxWidth:200});

    if( !objIndicator.isOverlay ) { 
      objMap.addOverlay(objIndicator);
      objIndicator.isOverlay = true;
    } else if( objIndicator.isHidden() ) { 
      objIndicator.show();
    }
  });

  return Pauly;
}



function createSoloEndPoint(floatEl) { 
  if( !floatEl ) { 
    return null;
  }
  var diveEl = getLatestDive(floatEl);
  if( !diveEl ) { 
    return null;
  }
  var float_id = floatEl.getAttribute("id");
  var lat = parseFloat(diveEl.getAttribute("lat"));
  var lon = parseFloat(diveEl.getAttribute("lon"));
  var epoint = new GLatLng(lat,lon);
  var ico = new GIcon(icons["sign"]);
  ico.image = ico.image+"?id="+float_id;
  var Otero = new GMarker( epoint,{icon:ico} );
  var html = '<div id="infoWindow">'+getDiveMetadata(diveEl)+"</div>";
  GEvent.addListener(Otero,"click",function() { 
    Otero.openInfoWindowHtml(html,{maxWidth:200});
  });
  return Otero;
}


function sort_numeric(a,b) { 
  return (a-b);
}


function createSoloPolyline(floatEl) { 
  if( !floatEl ) { 
    return false;
  }
  var points = [];
  var dives = floatEl.getElementsByTagName("dive");
  var keyed_dives = [];
  var dive_ids = [];

  // Build unsorted hash from floatEl record.
  for(var i=0,n=dives.length;i<n;i++) { 
    var did = parseInt(dives[i].getAttribute("surts"));
    var lat = parseFloat(dives[i].getAttribute("lat"));
    var lon = parseFloat(dives[i].getAttribute("lon"));
    keyed_dives[did] = new GLatLng(lat,lon);
    dive_ids.push(did);
  }

  // Sort by surface time (increasing)
  dive_ids.sort(sort_numeric);
  for(var i=0,n=dive_ids.length;i<n;i++) { 
    var ts = dive_ids[i];
    // alert(ts);
    points.push(keyed_dives[ts]);
  }

  var Pauly = new GPolyline(points);
  Pauly.float_id = floatEl.getAttribute("id");
  Pauly.dive_ids = dive_ids;

  GEvent.addListener(Pauly,"click",function(latlng) { 
    var V = getNearestVertex(Pauly,latlng);
    objIndicator.setLatLng(V);

    // Display metadata for dive clicked... 
    var html = '<div id="infoWindow">'+getDiveInfoForVertex(Pauly,V)+"</div>";
    objMap.openInfoWindowHtml(V,html,{maxWidth:200});

    if( !objIndicator.isOverlay ) { 
      objMap.addOverlay(objIndicator);
      objIndicator.isOverlay = true;
    } else if( objIndicator.isHidden() ) { 
      objIndicator.show();
    }
  });
  return Pauly;
}


function getStormInfoForVertex(poly,V) { 
  for(var i=0,n=poly.getVertexCount();i<n;i++) {
    if( poly.getVertex(i).equals(V) ) {
      var stormEl = getStormById(poly.storm_id);
      if( !stormEl ) {
        continue;
      }
      var pointEl = getPointByTimestamp(stormEl,poly.point_tss[i]);
      if( !pointEl ) {
        return null;
      }
      return getStormPointMetadata(poly.storm_id,pointEl);
    }
  }
  return null;
}


function getDiveInfoForVertex(poly,V) { 
  // var float_id = poly.float_id;
  // var dive_ids = poly.dive_ids;
  for(var i=0,n=poly.getVertexCount();i<n;i++) { 
    if( poly.getVertex(i).equals(V) ) { 
      var floatEl = getFloatById(poly.float_id);
      if( !floatEl ) { 
        continue;
      }
      var diveEl = getDiveByTimestamp(floatEl,poly.dive_ids[i]);
      if( !diveEl ) { 
        return null;
      }
      return getDiveMetadata(diveEl);
    }
  }
  return null;
}
  

function getNearestVertex(poly,latlng) { 
  var V = null;
  var D = null;
  for(var i=0,n=poly.getVertexCount();i<n;i++) { 
    var tV = poly.getVertex(i);
    var tD = tV.distanceFrom(latlng);
    if( D == null || tD < D ) { 
      V = tV;
      D = tD;
    }
  }
  return V;
}



/**
 * Writes current link
 */
function writeLinkForBookmarks() { 
  var mt = objMap.getCurrentMapType().getUrlArg();
  var ll = objMap.getCenter().toUrlValue();
  var zz = objMap.getZoom();

  var url = '?ll='+ll + '&zz='+zz + '&mt='+mt;
  // TODO -- add more parameters
  location.href = url;
}
  

/**
 * map initialization
 */
function init_map() { 
  var el = document.getElementById("Gmap");
  if( !el ) { 
    return;
  }
  if(!GBrowserIsCompatible()) {
    alert("Your browser is not compatible with google maps.");
    return false;
  }

  objMap = new GMap2(document.getElementById("Gmap"));
  objLayers = new LayerManager(objMap);

  objMap.addMapType(G_PHYSICAL_MAP);
  objMap.addControl(new GSmallMapControl());
  if( !get_url_parameter("id") ) { 
    objMap.addControl(new GMapTypeControl());
  }
  objMap.addControl(new GScaleControl());


  var zoom = get_url_parameter("zz");
  zoom = (!zoom) ? 7 : parseInt(zoom);

  var ll = get_url_parameter('ll');
  var latlng;
  if( !ll ) { 
    latlng = new GLatLng(20.55,-157.75);
  } else { 
    ll = ll.split(",");
    latlng = new GLatLng(parseFloat(ll[0]),parseFloat(ll[1]));
  }

  objMap.setCenter(latlng,zoom,G_PHYSICAL_MAP);

  var mt = get_url_parameter('mt');
  if( mt != null ) { 
    var types = objMap.getMapTypes();
    for(var m in types) { 
      if( types[m].getUrlArg() == mt ) { 
        objMap.setMapType(types[m]);
        break;
      }
    }
  }
}


function init_cache() { 
  GDownloadUrl('query.php?listFloats',function(data,code) {
    if( code != 200 ) {
      alert("listFloats failed (Code "+code+")");
      return false;
    }
    cached["listFloats"] = data;
    GEvent.trigger(cached,"listFloatsLoaded");
  });

  GDownloadUrl('query.php?listAltimetry',function(data,code) {
    if( code != 200 ) {
      alert("listAltimetry failed (Code "+code+")");
      return false;
    }
    cached["listAltimetry"] = data;
    GEvent.trigger(cached,"listAltimetryLoaded");
  });

  /*
  GDownloadUrl('query.php?listStorms',function(data,code) {
    if( code != 200 ) {
      alert("listStorms failed (Code "+code+")");
      return false;
    }
    cached["listStorms"] = data;
    GEvent.trigger(cached,"listStormsLoaded");
  });
  */
}


function init_icons() { 
  icons["first"] = new GIcon(G_DEFAULT_ICON,'./images/mmo.png');
  icons["first"].image = "/projects/rimpac/2008/images/mmo.png";
  icons["first"].shadow = null;
  icons["first"].iconSize = new GSize(14,14);
  icons["first"].shadowSize = null;
  icons["first"].iconAnchor = new GPoint(7,7);
  icons["first"].infoWindowAnchor = new GPoint(8,5);
  // icons["first"].printImage = null;
  // icons["first"].mozPrintImage = null;
  // icons["first"].printShadow = null;
  // icons["first"].transparent = null;
  // icons["first"].imageMap = null;
  // icons["first"].maxHeight = null;
  // icons["first"].dragCrossImage = null;
  // icons["first"].dragCrossSize = null;
  // icons["first"].dragCrossAnchor = null;

  icons["last"] = new GIcon(icons["first"],'./images/iflag_gr.gif');
  icons["last"].image = "/projects/rimpac/2008/images/iflag_gr.gif";
  icons["last"].iconSize = new GSize(18,18);
  icons["last"].iconAnchor = new GPoint(4,16);
  icons["last"].infoWindowAnchor = new GPoint(14,8);


  icons["sign"] = new GIcon(G_DEFAULT_ICON);
  icons["sign"].image = "/projects/rimpac/2008/images/sign_masker.php";
  icons["sign"].shadow = "/projects/rimpac/2008/images/sign_shadow.png";
  icons["sign"].iconSize = new GSize(28,28);
  icons["sign"].shadowSize = new GSize(40,28);
  icons["sign"].iconAnchor = new GPoint(9,27);
  // icons["sign"].infoWindowAnchor = new GPoint(24,19);
  icons["sign"].infoWindowAnchor = new GPoint(13,20);


  icons["depr"] = new GIcon(
    icons["first"], "/projects/rimpac/2008/images/tropical_depr.png");

  icons["depr"].shadow = "/projects/rimpac/2008/images/tropcal_shadow.png";
  icons["depr"].iconSize   = new GSize(50,50);
  icons["depr"].shadowSize = new GSize(50,50);
  icons["depr"].iconAnchor       = new GSize(25,25);
  icons["depr"].infoWindowAnchor = new GSize(25,25);

  icons["stor"] = new GIcon(
    icons["depr"], "/projects/rimpac/2008/images/tropical_stor.png");

  icons["cat1"] = new GIcon(
    icons["depr"], "/projects/rimpac/2008/images/tropical_cat1.png");

  icons["cat2"] = new GIcon(
    icons["depr"], "/projects/rimpac/2008/images/tropical_cat2.png");

  icons["cat3"] = new GIcon(
    icons["depr"], "/projects/rimpac/2008/images/tropical_cat3.png");

  icons["cat4"] = new GIcon(
    icons["depr"], "/projects/rimpac/2008/images/tropical_cat4.png");

  icons["cat5"] = new GIcon(
    icons["depr"], "/projects/rimpac/2008/images/tropical_cat5.png");


  // Added when polyline is clicked.
  objIndicator = new GMarker(new GLatLng(0,0),{icon:icons["first"]});
  objIndicator.isOverlay = false;
  GEvent.addListener(objIndicator,"click",function() { 
    objIndicator.hide();
  });
}


function getStormById(storm_id) { 
  if( !cached["listStorms"] ) {
    alert("Cached listStorms not found -- listen for listStormsLoaded");
    return false;
  }

  var dom = GXml.parse(cached["listStorms"]);
  var storms = dom.getElementsByTagName("storm");
  for(var i=0,n=storms.length;i<n;i++) {
    if( storms[i].getAttribute("id") == storm_id ) {
      return storms[i];
    }
  }
  return null;
}


function getFloatById(float_id) { 
  if( !cached["listFloats"] ) { 
    alert("Cached listFloats not found -- listen for listFloatsLoaded");
    return false;
  }

  var dom = GXml.parse(cached["listFloats"]);
  var floats = dom.getElementsByTagName("float");
  for(var i=0,n=floats.length;i<n;i++) {
    if( floats[i].getAttribute("id") == float_id ) {
      return floats[i];
    }
  }
  return null;
}


function getEarliestDive(floatEl) { 
  var dives = floatEl.getElementsByTagName("dive");
  var minIndex = 0;
  var minTime = dives[minIndex].getAttribute("surts");
  var minDive = dives[minIndex].getAttribute("ndive");

  for(var i=1,n=dives.length;i<n;i++) {
    var ts = dives[i].getAttribute("surts");
    var dn = dives[i].getAttribute("ndive");
    if( minDive >= dn && minTime > ts ) { 
      minTime = ts;
      minDive = dn;
      minIndex = i;
    } 
  }
  return dives[minIndex];
}


function getLatestDive(floatEl) { 
  if( !floatEl ) { 
    return null;
  }
  var dives = floatEl.getElementsByTagName("dive");
  var maxIndex = 0;
  var maxTime = dives[maxIndex].getAttribute("surts");
  var maxDive = dives[maxIndex].getAttribute("ndive");

  for(var i=1,n=dives.length;i<n;i++) {
    var ts = dives[i].getAttribute("surts");
    var dn = dives[i].getAttribute("ndive");
    if( maxDive <= dn || maxTime < ts ) { 
      maxTime = ts;
      maxDive = dn;
      maxIndex = i;
    } 
  }
  return dives[maxIndex];
}


function getPointByTimestamp(stormEl,timestamp) { 
  if( !stormEl ) {
    return null;
  }
  var points = stormEl.getElementsByTagName("point");
  for(var i=0,n=points.length;i<n;i++) { 
    if( timestamp == points[i].getAttribute("ts") ) {
      return points[i];
    }
  }
  return null;
}


function getDiveByTimestamp(floatEl,timestamp) { 
  if( !floatEl ) { 
    return null;
  }
  var dives = floatEl.getElementsByTagName("dive");
  for(var i=0,n=dives.length;i<n;i++) {
    if( timestamp == dives[i].getAttribute("surts") ) { 
      return dives[i];
    }
  }
  return null;
}


  
function displayDiveMetadata(diveEl) { 
  var targ = document.getElementById("metadata");
  if( !targ ) { 
    alert("Couldn't find metadata element in document.");
    return false;
  }
  targ.innerHTML = getDiveMetadata(diveEl);
  return true;
}


function displayFloatPlots(float_id)  { 
  var el = document.getElementById("plots");
  if( !el ) { 
    return false;
  }
  var profs = [
    "temperature", "salinity", "soundspeed",
    "acoustic", "wavespec"
  ];
  for(var i=0,n=profs.length; i<n; i++) { 
    if( !(float_id == 2 || float_id == 10) && i < 3) { 
      continue;
    }

    var img = new Image();
    img.src = "profile.php?id=" + float_id + "&prof=" + profs[i];
    el.appendChild(img);

    if( profs[i] == "acoustic" ) { 
      var img = new Image();
      img.src = "profile.php?id=" + float_id + "&prof=" + profs[i]+"&y1=1.5";
      el.appendChild(img);

      var img = new Image();
      img.src = "hprofile.php?id=" + float_id + "&prof=" + profs[i]+"&y=8";
      el.appendChild(img);
    }
  }
}



function getLatestStormPoint(stormEl) { 
  var maxTs = null;
  var ix = null;
  var points = stormEl.getElementsByTagName("point");
  for(var i=0,n=points.length;i<n;i++) { 
    var ts = parseInt(points[i].getAttribute("ts"));
    if( !maxTs || maxTs < ts ) {
      maxTs = ts;
      ix = i;
    }
  }
  return points[ix];
}


function displayStormMetadata(stormEl)  { 
  var targ = document.getElementById("metadata");
  if( !targ ) {
    alert("Couldn't find metadata element in document.");
    return false;
  } 
  var latest = getLatestStormPoint(stormEl);
  targ.innerHTML = getStormPointMetadata(stormEl.getAttribute("id"),latest);
  return true;
}


function displayFloatMetadata(floatEl)  { 
  if( !floatEl ) { 
    return null;
  }
  return displayDiveMetadata(getLatestDive(floatEl));
}


function getDiveMetadata(diveEl) { 
  var dispFloatN = diveEl.getAttribute("id");
  var dispDiveN = diveEl.getAttribute("ndive");

  var dobj = new Date(diveEl.getAttribute("surts")*1000);
  var dispTimestamp = dobj.toUTCString();

  var dispLocation = diveEl.getAttribute("lat") + "&deg;N, " +
                     (0-parseFloat(diveEl.getAttribute("lon"))) + "&deg;W";
  var dispMode = diveEl.getAttribute("phase");

  var appended = '';
  if( get_url_parameter("id") != dispFloatN ) { 
    appended = '<br/><a href="float.php?id='+dispFloatN+'>View Float Details</a>';
  }

  return 'Float # '+dispFloatN+'<br/>'+
   'Dive # '+dispDiveN+'<br/>'+
   'Mode: '+dispMode+'<br/>'+
   ''+dispTimestamp+'<br/>'+
   ''+dispLocation+''+appended;

}


function getStormPointMetadata(storm_id,pointEl) { 
  var txt = 'Storm Name: '+storm_id+'<br/>';

  var spd = parseInt(pointEl.getAttribute("spd"));
  var cog = parseInt(pointEl.getAttribute("cog"));
  var wnd = parseInt(pointEl.getAttribute("wnd"));
  var gst = parseInt(pointEl.getAttribute("gst"));

  var dobj = new Date(pointEl.getAttribute("ts")*1000);
  txt += dobj.toUTCString()+"<br/>";

  var dispLocation = pointEl.getAttribute("lat") + "&deg;N, " +
                     (0-parseFloat(pointEl.getAttribute("lon"))) + "&deg;W";
  txt += dispLocation+"<br/>";

  txt += "Category: "+pointEl.getAttribute("typ")+"<br/>";

  if( wnd ) {
    txt += "Wind (Sustained): "+wnd+" knots<br/>";
  }
  if( gst ) { 
    txt += "Wind (Gusts): "+gst+" knots<br/>";
  }
  if( spd && cog ) { 
    txt += "Traveling: "+spd+" knots at "+cog+"&deg;<br/>";
  }

  txt += '<a href="storm.php?sid='+storm_id+'>View Details</a>';

  return txt;
}

function updateOverlays() { 
  var el = document.getElementById("toggleAltimetry");
  if( cached["listAltimetry"] ) { 
    if( !el || el.checked ) { 
      objMap.addLatestAltimetry();
    } else { 
      objMap.removeLatestAltimetry();
    }
  }

  el = document.getElementById("toggleTracks");
  if( cached["listStorms"] ) { 
    if( !el || el.checked ) { 
      objMap.addStormTracks();
    } else { 
      objMap.removeStormTracks();
    }
  }

  el = document.getElementById("toggleFloats");
  if( cached["listFloats"] ) { 
    if( !el || el.checked ) { 
      objMap.addSoloFloats();
    } else { 
      objMap.removeSoloFloats();
    }
  }

  el = document.getElementById("toggleOpsArea");
  if( !el || el.checked ) { 
    objMap.addRimpacOpsArea();
  } else { 
    objMap.removeRimpacOpsArea();
  }

  el = document.getElementById("toggleNrlNowcast");
  if( el && el.checked ) { 
    objMap.addNrlNowcast();
  } else { 
    objMap.removeNrlNowcast();
  }
}


function displayLatestTimestamp(elID) { 
  var el = document.getElementById(elID);
  if( !el ) { 
    return;
  }

  var dom = GXml.parse(cached["listAltimetry"]);
  var stamps = dom.getElementsByTagName("stamp");
  var maxStamp = null;
  for(var i=0,n=stamps.length;i<n;i++) {
    var stamp = stamps[i].firstChild.nodeValue;
    if( !maxStamp || stamp.toString() > maxStamp ) {
      maxStamp = stamp.toString();
    }
  }
  if( !maxStamp ) {
    return false;
  }
  var yr = maxStamp.substr(0,4);
  var mo = maxStamp.substr(4,2);
  var da = maxStamp.substr(6,2);
  el.innerHTML = yr+"-"+mo+"-"+da;
}



/**
 * page initialization
 */
function doPageLoad() { 
  init_map();
  init_cache();

  GEvent.addListener(cached,"listFloatsLoaded",init_floats_menu);
  // GEvent.addListener(cached,"listStormsLoaded",init_storms_menu);

  if( location.pathname.indexOf("plotsbyvar.php") >= 0 ) { 
    loadPlotsByVariable();
  }

  if( !objMap ) { 
    return;
  }

  init_icons();
  register_listeners();


  GEvent.addListener(cached,"listFloatsLoaded",function() { 
    // init_floats_menu();
    updateOverlays();

    var float_id = get_url_parameter("id");
    if( float_id ) { 
      var floatEl = getFloatById(float_id);
      if( !floatEl ) { 
        return null;
      }
      displayFloatMetadata(floatEl);
      displayFloatPlots(float_id);
    }
  });

  GEvent.addListener(cached,"listAltimetryLoaded",function() { 
    displayLatestTimestamp("altimetryTime");
    updateOverlays();
  });

  GEvent.addListener(cached,"listStormsLoaded",function() { 
    // init_storms_menu();
    updateOverlays();

    var storm_id = get_url_parameter("sid");
    if( storm_id ) { 
      var stormEl = getStormById(storm_id);
      if( !stormEl ) { 
        return null;
      }
      displayStormMetadata(stormEl);
    }
  });
}

function register_listeners() { 
  var el = document.getElementById("toggleAltimetry");
  if( el ) { 
    el.onclick = function() { el.blur(); }
    el.onblur = updateOverlays;
  }

  /*
  el = document.getElementById("toggleTracks");
  if( el ) { 
    el.onclick = function() { el.blur(); }
    el.onblur = updateOverlays;
  }
  */

  el = document.getElementById("toggleFloats");
  if( el ) { 
    el.onclick = function() { el.blur(); }
    el.onblur = updateOverlays;
  }

  el = document.getElementById("toggleOpsArea");
  if( el ) { 
    el.onclick = function() { el.blur(); }
    el.onblur = updateOverlays;
  }

  el = document.getElementById("toggleNrlNowcast");
  if( el ) { 
    el.onclick = function() { el.blur(); }
    el.onblur = updateOverlays;
  }
}

window.onload = doPageLoad;
window.onunload = GUnload;
window.onbeforeunload = GUnload;
