// Provide the XMLHttpRequest class for IE 5.x-6.x:
if( typeof XMLHttpRequest == "undefined" ) XMLHttpRequest = function() {
  try { return new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {}
  try { return new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {}
  try { return new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {}
  throw new Error( "This browser does not support XMLHttpRequest." )
};
DENSITY = {
  '9muq' : 1,
  '9mup' : 1,
  '9mus' : 1,
  '9mur' : 1,
  '9m'   : 1,
  '9mut' : 1,
  '9muw' : 1,
  '9mux' : 1,
  '9q5f' : 1,
  '9muz' : 1,
  '9qhs' : 1,
  '9qh3' : 1,
  '9x'   : 1,
  '9qhd' : 1,
  '9q56' : 1,
  '9mue' : 1,
  '9mud' : 1,
  '9mug' : 1,
  '9muf' : 1,
  '9q'   : 1,
  '9muu' : 1,
  '9r'   : 1,
  '9q73' : 1,
  '87'   : 1,
  '9q5d' : 1,
  '9q8y' : 1,
  '9qcg' : 1,
  '9qh'  : 1,
  '9qk'  : 1,
  '9qcd' : 1,
  '9qd'  : 1,
  '9qf'  : 1,
  '9qh0' : 1,
  '9qc'  : 1,
  '9qb'  : 1,
  '9qcs' : 1,
  '9qcv' : 1,
  '9q9m' : 1,
  '9'    : 1,
  '9r1'  : 1,
  '9q9k' : 1,
  '9qc6' : 1,
  '9qh6' : 1,
  '9qh4' : 1,
  '9q5v' : 1,
  '9qh2' : 1,
  '9qcu' : 1,
  '9q97' : 1,
  '9qh1' : 1,
  '9q9h' : 1,
  '9x0'  : 1,
  '9q9j' : 1,
  '9qk6' : 1,
  '9qh8' : 1,
  '9q9n' : 1,
  '9q9q' : 1,
  '9q9p' : 1,
  '9q5b' : 1,
  '9q9r' : 1,
  '9q5c' : 1,
  '8'    : 1,
  '9q9y' : 1,
  '9mu'  : 1,
  '9qdc' : 1,
  '9qh9' : 1,
  '9q5e' : 1,
  'c'    : 1,
  '9qc8' : 1,
  '87z'  : 1,
  'd'    : 1,
  '9mv'  : 1,
  '9qce' : 1,
  '9qc2' : 1,
  '9qc1' : 1,
  '9qc0' : 1,
  '9q9'  : 1,
  '9q8'  : 1,
  '9q5'  : 1,
  '9q4'  : 1,
  '9q7'  : 1,
  '9q6'  : 1,
  '9qhc' : 1
}
function resize() {
  var height = document.getElementById("body").clientHeight - document.getElementById("header").offsetHeight;
  document.getElementById("map").style.height = height + "px";
  addNeighborhood();
}
function load() {
  if (GBrowserIsCompatible()) {
    map = new GMap2(document.getElementById("map"));
    geocoder = new GClientGeocoder();
    map.setCenter(new GLatLng(37.757687,  -122.450867), 13);
    map.addControl(new GLargeMapControl());
    map.addControl(new GMapTypeControl());
    map.enableScrollWheelZoom();
    GEvent.addListener(map, "moveend", onmoveend);
    window.onresize = resize;
    window.setTimeout(resize, 0);
  } else {
    alert('upgrade your browser');
  }
}
function showSearchAddress() {
  var searchbox = document.getElementById("searchbox");
  var address = searchbox.value;
  showAddress(address);
  return false;
}
function showAddress(address) {
  geocoder.getLatLng(
    address,
    function(point) {
      if (!point) {
        alert(address + " not found");
      } else {
        map.setCenter(point, 13);
      }
    }
  );
  return false;
}
function isVisible(geohash) {
  var bounds = map.getBounds();
  var north = bounds.getNorthEast().lat();
  var east = bounds.getNorthEast().lng();
  var south = bounds.getSouthWest().lat();
  var west = bounds.getSouthWest().lng();
  var box = decodeGeoHash(geohash);
  if (box.latitude[1] > south && box.latitude[0] < north && box.longitude[1] > west && box.longitude[0] < east) {
    return true;
  } else {
    return false;
  }
}
function getNeighborhood(precision) {
  var sw = encodeGeoHash(map.getBounds().getSouthWest().lat(), map.getBounds().getSouthWest().lng()).substr(0, precision);
  var boxes = [];
  boxes[boxes.length] = sw;
  while (isVisible(sw)) {
    sw = calculateAdjacent(sw, 'right');
    boxes[boxes.length] = sw;
    var tmp = sw;
    while (isVisible(tmp)) {
      tmp = calculateAdjacent(tmp, 'top');
      boxes[boxes.length] = tmp;
    }
  }
  return boxes;
}
var cache = {};
function getPrecision(geohash) {
  for (var i = 1; i <= 4; i++) {
    if (DENSITY[geohash.substr(0, i)] == null) {
      return i;
    }
  }
  return 5;
}
ZOOM_TO_MAX_PRECISION = {
    0  : 1,
    1  : 1,
    2  : 1,
    3  : 1,
    4  : 1,
    5  : 2,
    6  : 2,
    7  : 2,
    8  : 3,
    9  : 3,
    10 : 4,
    11 : 4,
    12 : 4,    
    13 : 5,
    14 : 5,
    15 : 5,
    16 : 5,
    17 : 5,
    18 : 5,
    19 : 5
}
function onmoveend() {
  window.setTimeout(addNeighborhood, 0);
}
function addNeighborhood() {
  var precision = ZOOM_TO_MAX_PRECISION[map.getZoom()];
  var neighborhood = getNeighborhood(precision);
  for (var i = 0; i < neighborhood.length; i++) {
    var geohash = neighborhood[i];
    geohash = geohash.substr(0, getPrecision(geohash));
    for (var k = 1; k <= geohash.length; k++) {
      var subhash = geohash.substr(0, k);
      if (cache[subhash] == null || cache[subhash] == 0) {
        cache[subhash] = 1;
        addHash(subhash);
      }
    }
  }
}
MARKER_ZOOM = [
    100000, 1,
    10000,  7,
    5000,   8,
    2500,   9,
    1000,   10,
    750,    11,
    500,    12
];
function onLookupSuccess(response) {
  var geohash = response[0];
  var zoom_to_markers = {};
  for (var i = 1; i < response.length; i++) {
      var name = response[i][0];
      var employer = response[i][1];
      var occupation = response[i][2];
      var location = response[i][3];
      var total = response[i][4];
      var box = decodeGeoHash(location);
      var lat = box.latitude[2];
      var lng = box.longitude[2];
      var contributorHTML = "<table><tr><td colspan=2><b>" + name + "</b></td></tr>" + "<tr><td colspan=2>" + occupation + "</td></tr><tr><td colspan=2>" + employer + "</td></tr>";
      var contributions = response[i][5];
      for (var k = 0; k < contributions.length/2; k+=2) {
        var amount = contributions[k];
        var transaction_date = contributions[k+1];
        contributorHTML = contributorHTML + "<tr><td>" + amount + "</td><td>" + transaction_date + "</td></tr>"
      }
      contributorHTML = contributorHTML + "</table>"
      var marker = new GMarker(new GLatLng(lat, lng));
      marker.bindInfoWindowHtml(contributorHTML);
      var zoom = 13;
      for (var k = 0; k < MARKER_ZOOM.length/2; k+=2) {
        if (total >= MARKER_ZOOM[k]) {
          zoom = MARKER_ZOOM[k+1];
          break;
        }
      }
      var markers = zoom_to_markers[zoom];
      if (markers == null) {
        zoom_to_markers[zoom] = [marker];
      } else {
        markers[markers.length] = marker;
      }
  }
  var mgr = new MarkerManager(map);
  for (key in zoom_to_markers) {
    mgr.addMarkers(zoom_to_markers[key], key);
  }
  mgr.refresh();
}
function addHash(geohash) {
  var request = new XMLHttpRequest();
  var url = "/lookup?" + geohash;
  request.open("GET", url, true);
  request.onreadystatechange=function() {
    var done = 4, ok = 200;
    if (request.readyState == done) {
      if (request.status == ok) {
        response = eval(request.responseText);
        if (response == null) {
          alert('request for ' + geohash + ' failed');
        } else {
          onLookupSuccess(response);
        }
      } else {
        cache[geohash] = 0;
      }
    }
  }
  request.send(null);
}
