// -*- mode: javascript; coding: utf-8 -*-

var MOOLI = MOOLI ? MOOLI : {};

MOOLI.Pubmap = function() {
  // package-global variables

  var G = google.maps,		// namespace alias
      M = Math;			// namespace alias

  function marker_path(pubdata) {
    return '/static/markers/' +
      (pubdata.isclosed ? 'red/' : 'blue/') +
      (pubdata.score >= 1 && pubdata.score <= 99 ? 'marker' + pubdata.score : 'blank') +
      '.png';
  }

  return function(element) {
    var pubs = {},              // has of pubs and their markers
      map = new G.Map($(element)[0], { // the map object
        zoom: 7,
            center: new G.LatLng(53, -1),
            mapTypeId: G.MapTypeId.ROADMAP
            }),
    infowindow = new G.InfoWindow(); // the pop-up information window

    // This is called to (re)paint the map viewport
    function update_markers() {
      // Here we do an Ajax call to retrieve a list of pubs within the viewport

      // Get visible area of map
      var bounds = map.getBounds(),
	ne = bounds.getNorthEast(), sw = bounds.getSouthWest(),
	n = ne.lat(), s = sw.lat(), e = ne.lng(), w = sw.lng(),

        // We want to enlarge the bounding box so that the co-ordinates are more
        // "round" and thus more likely to be cached

	span = bounds.toSpan(), // doesn't go funny when we wrap round the world
	lng_round = M.pow(2, M.floor(M.log(span.lng()) / M.LN2) - 2),
	lat_round = M.pow(2, M.floor(M.log(span.lat()) / M.LN2) - 2);

      n = M.ceil(n / lat_round) * lat_round;
      e = M.ceil(e / lng_round) * lng_round;
      s = M.floor(s / lat_round) * lat_round;
      w = M.floor(w / lng_round) * lng_round;

      $.ajax({
	type: 'GET',
	    url: '/pubajax/list/' + n + '/' + e + '/' + s + '/' + w,
	    dataType: 'json',
	    success: function(data, textStatus) { show_markers(data); }
	  // error: function(XMLHttpRequest, textStatus, errorThrown) {},
	});
    }

    // this is called on successful Ajax call for an updated pub list
    function show_markers(data) {
      var new_pubs = data.pubs;

      $.each(new_pubs, function(id, pubdata) {
	  // This does a retrieve-and-delete, so that "pubs" will eventually
	  // only contain those pubs that aren't in "new_pubs".
	  var old = pubs[id]; delete pubs[id];
	  if(old) {
	    // existing marker on map, do nothing but copy it
	    pubdata.marker = old.marker;
	  } else { // new marker, add
            pubdata.marker = new G.Marker({
              position: new G.LatLng(pubdata.latitude, pubdata.longitude),
                  map: map,
                  icon: marker_path(pubdata)
                  });

	    // when we click on a marker, do an AJAX call to get the description, then pop-up.
	    G.event.addListener(pubdata.marker, 'click', function() {
		// "this" is the marker
		marker = this;
                infowindow.close(); // close window on previous pub
		$.ajax({
		  type: 'GET',
		      url: '/pubajax/pub/' + id,
		      dataType: 'html',
		      success: function(data) {
                      infowindow.setContent(data);
                      infowindow.open(map, marker);
		    }
		  });
	      });

	  }
	});
      // any markers left in pubs need to be removed
      $.each(pubs, function(id, pubdata) { pubdata.marker.setMap(null); });
      // finally, the just-downloaded list replaces the old list
      pubs = new_pubs;

    }

    G.event.addListener(map, 'bounds_changed', update_markers);
  };

}();

$(function() {
    MOOLI.Pubmap('#map');
  });
