google.load("maps", "2");

Office = function(officeEl) {
  this.zoomLevel = 15;
  this.selected = officeEl.className == 'selected';
  this.el = officeEl;
  this.id = officeEl.id;
  this.label = officeEl.getElementsByTagName('A')[0].innerHTML;
  this.address = officeEl.getElementsByTagName('ADDRESS')[0].innerHTML;
  this.instructions = '';
  var instructionsList = officeEl.getElementsByTagName('DIV');
  for (var i=0; i<instructionsList.length; i++) {
    var instEl = instructionsList[i];
    if (instEl.getAttribute('name') == 'instructions') {
      this.instructions = instEl.innerHTML;
      break;
    }
  }
  this.marker = null;
  this.data = {};
  var inputs = officeEl.getElementsByTagName('INPUT');
  for (var i=0; i<inputs.length; i++) {
    this.data[inputs[i].name] = inputs[i];
  }

  this.setup = function(latLng) {
    this.latLng = latLng;
    var opt = {
      title: this.label,
      clickable: true
    }; 
    this.marker = new google.maps.Marker(latLng, opt);
    map.addOverlay(this.marker);
    this.marker.show();
    this.windowHtml = ('<div>' + this.el.innerHTML + '<form onsubmit="offices.route(this.source, \'' + this.id + '\'); return false;"><label class="source">Directions from:</label><br/><input name="source"/> <input type="submit" value="Go"/></form></div>');
    this.marker.bindInfoWindowHtml(this.windowHtml);
    if (this.selected) {
      this.focus();
    }
  }

  this.focus = function() {
    this.marker.show();
    map.setCenter(this.marker.getLatLng(), this.zoomLevel);
    this.marker.openInfoWindowHtml(this.windowHtml);
  }

  this.route = function(address) {
    var this_ = this;
    directions.clear();
    this_.directionsLoad = google.maps.Event.addListener(directions, 'load', function (){
      document.getElementById('directions-anchor').style.display = 'block';
      offices.hide();
      google.maps.Event.removeListener(this_.directionsLoad);
      google.maps.Event.removeListener(this_.directionsError);
      var instructionEl = document.getElementById('instructions');
      if (this_.instructions.length == 0) {
        instructionEl.style.display = 'none';
      } else {
        instructionEl.innerHTML = this_.instructions;
        instructionEl.style.display = 'block';
      }
    });
    this_.directionsError = google.maps.Event.addListener(directions, 'error', function (){
      document.getElementById('directions-anchor').style.display = 'none';
      alert("An error occurred while calculating the route");
      offices.show();
      google.maps.Event.removeListener(this_.directionsLoad);
      google.maps.Event.removeListener(this_.directionsError);
    });

    this.marker.closeInfoWindow();
    var latLng = this.marker.getLatLng();
    var waypoints = [address, this.address + ' @' + latLng.y + ', ' + latLng.x]
//    var waypoints = [address, this.address]
    directions.loadFromWaypoints(waypoints);
  }

  var lat = this.data['latitude'];
  var lng = this.data['longitude'];
  if (lat && lng) {
    lat = parseFloat(lat.value);
    lng = parseFloat(lng.value);
    this.latLng = new google.maps.LatLng(lat, lng);
  } else {
    this.latLng = null;
  }
}

Offices = function() {
  this.locations = {};
  this.locationQueue = [];
  this.hidden = [];
  this.running = false;
  this.loadTimeout = 100;

  this.add_location = function(office) {
    var this_ = this;
    if (office.latLng) {
      office.setup(office.latLng);
      this_.locations[office.id] = office;
      this.next_location();
      return;
    }
    if (!office.address) {
      office.el.innerHTML = 'Could not find ' + office.label;
      this.next_location();
      return;
    }
    geo.getLatLng(office.address, function (latLng) {
      if (!latLng) {
        office.el.innerHTML = 'Could not find ' + office.label + ' (' + office.address + ')';
        setTimeout('this_.next_location();', this_.loadTimeout);
        return;
      }
      office.setup(latLng);
      this_.locations[office.id] = office;
      setTimeout('this_.next_location();', this_.loadTimeout);
    });
  }

  this.next_location = function() {
    if (!this.locationQueue.length) {
      this.running = false;
      return;
    }
    var address = this.locationQueue.shift();
    this.add_location(address);
  }

  this.focus = function(id) {
    var office = this.locations[id];
    if (!office) {
      return;
    }
    office.focus();
  }

  this.push = function(office) {
    this.locationQueue.push(office);
    if (!this.running) {
      this.running = true;
      this.next_location();
    }
  }

  this.route = function(address, id) {
    var office = this.locations[id];
    if (!office) return;
    office.route(address.value);
  }

  this.show = function() {
    while (this.hidden.length) {
      this.hidden.shift().marker.show();
    }
  }

  this.hide = function(office) {
    for (var id in this.locations) {
      var office = this.locations[id];
      office.marker.hide();
      this.hidden.push(office);
    }
  }
}

var map = null, directions = null, geo = null, offices = new Offices();

// Call this function when the page has been loaded
function initialize() {
  map = new google.maps.Map2(document.getElementById("map"));
  geo = new google.maps.ClientGeocoder();
  map.addControl(new google.maps.LargeMapControl());
  map.addControl(new google.maps.MapTypeControl());
  map.setCenter(new google.maps.LatLng(39.719, -104.951), 8);
  directions = new google.maps.Directions(map, document.getElementById('directions'));

  if (document.all) {
    var lists = document.getElementsByTagName('UL');
    var officeLists = [];
    for (var l=0; l<lists.length; l++) {
      if (lists[l].name == 'offices') {
        officeLists.push(lists[l]);
      }
    }
  } else {
    var officeLists = document.getElementsByName('offices');
  }
  for (var o=0; o<officeLists.length; o++) {
    addresses = officeLists[o].getElementsByTagName('LI');
    for (var i=0; i<addresses.length; i++) {
      officeEl = addresses[i];
      office = new Office(officeEl);
      offices.push(office);
    }
  }
}

google.setOnLoadCallback(initialize);

