var map;
var map_markers_hash = {};
var map_targets_info_hash = {};

// map_targets_info:
//   A list of info for all the unique targets to display on the map.
// map_target_info: 
//   (optional) An target to initially snap to and show an info window for.  
//   This target must be included in the map_targets_info colleciton. 
function init_map() {
  if (GBrowserIsCompatible()) {
    // Initilaize the map and add controls.
    map = new GMap2($('map'));
    map.addControl(new GLargeMapControl());
    map.addControl(new GMapTypeControl());
    
    // If there were some targets, show those, 
    // If there was a featured target, snap to it
    // Otherwise show the whole US.
    if(typeof(map_targets_info) != "undefined") {
      // Horrible evil hack for figuring out the map box to use.
      var lats = map_targets_info.map(function(info) { return info.lat }).sort(function(a,b){return a - b});
      var lngs = map_targets_info.map(function(info) { return info.lng }).sort(function(a,b){return a - b});
      var l = lats.length;
      var s = lats[Math.round((l-1) * 0.025)];
      var w = lngs[Math.round((l-1) * 0.025)];
      var n = lats[Math.round((l-1) * 0.975)];
      var e = lngs[Math.round((l-1) * 0.975)];
      var ns_delta = n - s;
      var ew_delta = e - w;
      var pad = 0.05;

      // Center and zoom on the bounding rect derived above.
      center_and_zoom_on_rect(s - (pad * ns_delta), w - (pad * ew_delta), 
                              n + (pad * ns_delta), e + (pad * ew_delta));
      
      // Create markers for each target.
      for(i=0; i < map_targets_info.length; i++) {
        var target_info = map_targets_info[i];
        create_target_marker(target_info);
      }
    } else {
      map.setCenter(new GLatLng(37.0625, -95.67706), 4);
    }
    
    // Ensure that if there is a featured target there is has a marker and snap 
    // to it.
    if(typeof(map_target_info) != "undefined") {
      snap_to_marker(map_target_info.id);
    }
  }
}

window.onload = init_map;
window.onunload = GUnload;

// Create a new marker target corresponding to the target_info hash, add it
// to the map and the global marker collections.
function create_target_marker(target_info) {
  var marker = add_marker(target_info.lat, target_info.lng, target_info.html);
  map_markers_hash[target_info.id] = marker;
  map_targets_info_hash[target_info.id] = target_info;
}

// create_target_marker iff there is not allread a marker corresponding to
// target_info.
function ensure_target_marker(target_info) {
  var existing_marker = map_markers_hash[map_target_info.id];
  if(typeof(existing_marker) == "undefined") {
    create_target_marker(target_info)
  }
}

// Snap to the existing marker corresponding to target_id.
function snap_to_marker(target_id) {
  var marker = map_markers_hash[target_id];
  var target_info = map_targets_info_hash[target_id];
  map.panTo(new GLatLng(target_info.lat, target_info.lng));
  marker.openInfoWindowHtml(target_info.html);
}

// Create and add to the map a GMarker corresponding to the given lat, lng, and
// info window html.
// Returns the created GMarker.
function add_marker(lat, lng, html) {
  var marker = new GMarker(new GLatLng(lat, lng));
  GEvent.addListener(marker, 'click',
    function() { marker.openInfoWindowHtml(html); } 
  );  
  map.addOverlay(marker);
  return marker;
}

// Adjust the map window to encopass the rect described by the four floats.
function center_and_zoom_on_rect(s, w, n, e) {
  bounds = new GLatLngBounds(new GLatLng(s,w), new GLatLng(n, e));
  map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));
}
