/* Base objects */
var WalkDBMap = {
   cookieName : "walkDBSavedLocation",
   defaultAddresses : ["London", "New York", "Paris", "Rome", "Sydney", "Montreal"],
   defaultZoom : 13,
   fired : false,
   toBeNotified : [],
   /* Register a function to be called after the map is loaded */
   ready : function(callback) {
      if (WalkDBMap.fired) {
         callback();
      } else {
         WalkDBMap.toBeNotified.push(callback);
      }
   },
   /* Map is now loaded, call waiting functions */
   fireReady : function() {
      WalkDBMap.fired = true;
      C.callEach(WalkDBMap.toBeNotified);
      WalkDBMap.toBeNotified = null;
   },
   /* Pins identifying routes, as shown */
   routePins : []
}

/* Google Maps API dependent objects */
WalkDBMap.ready(function() {
   /* Add attributes and methods to the WalkDBMap object */
   WalkDBMap.geocoder = new google.maps.ClientGeocoder();
   /* Centre the map on a lat/long pair */
   WalkDBMap.centre = function(lat, long, zoom) {
      WalkDBMap.centreToPoint(new google.maps.LatLng(lat, long), zoom);
   };
   /* Centre the map on a point object */
   WalkDBMap.centreToPoint = function(point, zoom) {
      var thisZoom = WalkDBMap.defaultZoom;
      if (zoom) {
         thisZoom = zoom;
      }
      WalkDBMap.map.setCenter(point, thisZoom);
   };
   /* Centre to values in a literal object */
   WalkDBMap.centreToObject = function(locationInfo) {
      var lat = locationInfo.lat;
      var long = locationInfo.long;
      var zoom = locationInfo.zoom;
      
      WalkDBMap.centre(lat, long, zoom);
   };
   /* Automatically choose an interesting centre point, at random */
   WalkDBMap.autoCentreAtRandom = function() {
      var index = Math.floor(Math.random() * WalkDBMap.defaultAddresses.length);
      var selectedAddress = WalkDBMap.defaultAddresses[index];
      WalkDBMap.centreToAddress(selectedAddress);
   };
   /* Try and centre the map based on Google's ClientLocation */
   WalkDBMap.autoCentre = function() {
      if (google.loader.ClientLocation) {
         var lat = google.loader.ClientLocation.latitude;
         var lng = google.loader.ClientLocation.longitude;
         WalkDBMap.centre(lat, lng);
      } else {
         WalkDBMap.autoCentreAtRandom();
      }
   };
   /* Centre the map on a particular address */
   WalkDBMap.centreToAddress = function(address, zoom, notFoundCallback) {
      WalkDBMap.geocoder.getLatLng(address, function(point) {
         if (!point) {
            if (notFoundCallback) {
               notFoundCallback(address);
            } else {
               alert(address + " not found");
            }
         } else {
            WalkDBMap.centreToPoint(point, zoom);
         }
      });
   };
   /* From a list of latlngs, find the centre and sensible zoom level */
   WalkDBMap.getRangeInfo = function(points) {
      var bounds = new google.maps.LatLngBounds();
      C.each(points, function(point) {
         bounds.extend(point);
      });
      return bounds;
   };
   /* Centre the map on the centre of the range specified.  Map will also zoom automatically */
   WalkDBMap.centreOnRange = function(points) {
      var rangeInfo = WalkDBMap.getRangeInfo(points);
      
      WalkDBMap.centreToPoint(rangeInfo.getCenter(), WalkDBMap.map.getBoundsZoomLevel(rangeInfo));
   };
   /* Get the centre of the map, as it is */
   WalkDBMap.getCentre = function() {
      return WalkDBMap.map.getCenter();
   };
   /* Get current zoom level */
   WalkDBMap.getZoom = function() {
      return WalkDBMap.map.getZoom();
   }
   /* Set the map when loaded */
   WalkDBMap.setMap = function(map) {
      WalkDBMap.map = map;
      map.addControl(new google.maps.LargeMapControl());
      map.addControl(new google.maps.MapTypeControl());
      
      var adManagerOptions = {maxAdsOnPage: 1};
      var adManager = new google.maps.AdsManager(map, "ca-pub-1157030937396536", adManagerOptions);
      adManager.enable();
   };
   /* Register a listener event on the map */
   WalkDBMap.registerListener = function(eventType, callback) {
      GEvent.addListener(WalkDBMap.map, eventType, callback);
   };
   /* Add a control to the map */
   WalkDBMap.addControl = function(control) {
      WalkDBMap.map.addControl(control);
   };
   /* Add a div or something to the map */
   WalkDBMap.appendToMap = function(container) {
      WalkDBMap.map.getContainer().appendChild(container);
   };
   /* Draw a route line */
   WalkDBMap.drawPoints = function(points) {
      var line = new google.maps.Polyline(points);
      WalkDBMap.map.addOverlay(line);
   };
   /* Already pinned? */
   WalkDBMap.alreadyPinned = function(point) {
      for (var i = 0; i < WalkDBMap.routePins.length; i++) {
         var otherPoint = WalkDBMap.routePins[i].pinPoint;
         if (otherPoint.routeId == point.routeId) {
            return true;
         }
      }
      return false;
   };
   /* Pin route location - i.e. location of a route, not used within a route */
   WalkDBMap.pinRouteLocation = function(point, callback) {
      if (WalkDBMap.alreadyPinned(point)) {
         // do nothing
      } else {
         var marker = new google.maps.Marker(point);
         WalkDBMap.routePins.push({pinPoint: point, pinMarker: marker});
         GEvent.addListener(marker, "click", callback);
         WalkDBMap.map.addOverlay(marker);
      }
   };
   /* Pin route locations */
   WalkDBMap.pinRouteLocations = function(points, callback) {
      C.each(points, function(point) {
         WalkDBMap.pinRouteLocation(point, function() {
            callback(point);
         });
      });
   };
   /* Clear ajax markers */
   WalkDBMap.clearAjaxRoutes = function() {
      C.each(WalkDBMap.routePins, function(pin) {
         WalkDBMap.map.removeOverlay(pin.pinMarker);
      });
      WalkDBMap.routePins = [];
   };
   /* AJAX request to get HTML for info bubble of a ajax route */
   WalkDBMap.getAndShowAjaxRouteInfoBubble = function(point) {
      var routeId = point.routeId;
      $.ajax({
         type: "POST",
         url: "/api/get_route_info_bubble",
         data: {
            route_id: routeId
         },
         dataType: "html",
         success: function(msg) {
            WalkDBMap.map.openInfoWindow(point, msg);
         }
      });
   };
   /* Do an AJAX call to find routes */
   WalkDBMap.showAjaxRoutes = function(currentRouteId) {
      var zoomLevel = WalkDBMap.map.getZoom();
      if (zoomLevel >= 10) {
         var bounds = WalkDBMap.map.getBounds();
         var southWest = bounds.getSouthWest();
         var northEast = bounds.getNorthEast();
         $.ajax({
            type: "POST",
            url: "/api/get_routes_in_bounds",
            data: {
               sw: southWest,
               ne: northEast
            },
            dataType: "json",
            success: function(msg) {
               var latlngs = C.filterNotNull(C.map(msg.routes, function(route) {
                  var latlng = new google.maps.LatLng(route.lat, route.lng);
                  latlng.routeId = route.routeId;
                  if (route.routeId != currentRouteId) {
                     return latlng;
                  } else {
                     return null;
                  }
               }));
               WalkDBMap.pinRouteLocations(latlngs, function(point) {
                  WalkDBMap.getAndShowAjaxRouteInfoBubble(point);
               });
            }
         });
      } else {
         WalkDBMap.clearAjaxRoutes();
      }
   };
   /* Stop showing routes available */
   WalkDBMap.stopShowingAjaxRoutes = function() {
      google.maps.Event.removeListener(WalkDBMap.ajaxRouteLoader);
      WalkDBMap.clearAjaxRoutes();
   };
   /* Start showing routes available on this map selection */
   WalkDBMap.startShowingAjaxRoutes = function(currentRouteId) {
      WalkDBMap.showAjaxRoutes(currentRouteId);
      WalkDBMap.ajaxRouteLoader = google.maps.Event.addListener(WalkDBMap.map, "moveend", function() {
         WalkDBMap.showAjaxRoutes(currentRouteId);
      });
   };
});

/* WalkDB object */
var WalkDB = {
};
WalkDBMap.ready(function() {
   WalkDB.parseLatlngStr = function(latlngStr) {
      var splitted = latlngStr.split(',');
      return new google.maps.LatLng(parseFloat(splitted[0]), parseFloat(splitted[1]));
   };
   WalkDB.parseLatlngStrs = function(latlngStrs) {
      var latlngs = [];
      C.each(latlngStrs, function(latlngStr) {
         latlngs.push(WalkDB.parseLatlngStr(latlngStr));
      });
      return latlngs;
   };
   WalkDB.literalToLatlng = function(literal) {
      return new google.maps.LatLng(literal.lat, literal.lng);
   };
   WalkDB.literalsToLatlngs = function(literals) {
      var latlngs = [];
      C.each(literals, function(literal) {
         latlngs.push(WalkDB.literalToLatlng(literal));
      });
      return latlngs;
   };
   WalkDB.kilometersToMiles = function(distanceInKm) {
      return distanceInKm * 0.6214;
   };
});

/* Info panel helper */
var InfoPanel = {
};
$(function() {
   /* Setup, to be called on-load */
   InfoPanel.initialise = function() {
      $('.info-block').filter('.collapsed').each(function(idx) {
         var titleText = $(this).find('h3').text();
         InfoPanel.markCollapsed($(this), titleText);
      });
      $('.info-block').filter('.collapseable').each(function(idx) {
         var titleText = $(this).find('h3').text();
         InfoPanel.markCollapseable($(this), titleText);
      });
   };
   /* Mark a block as collapsed, give option to expand */
   InfoPanel.markCollapsed = function(block, titleText) {
      block.find('.info-block-content').hide('slow');
      var blockTitle = block.find('h3').empty();
      blockTitle.append(titleText + ' (');
      $('<a href="#" class="toggle-button">Show</a>').appendTo(blockTitle).click(function() {
         InfoPanel.markCollapseable(block, titleText);
         return false;
      });
      blockTitle.append(')');
   };
   /* Mark a block as uncollapsed, give option to collapse */
   InfoPanel.markCollapseable = function(block, titleText) {
      block.find('.info-block-content').show('slow');
      var blockTitle = block.find('h3').empty();
      blockTitle.append(titleText + ' (');
      $('<a href="#" class="toggle-button">Hide</a>').appendTo(blockTitle).click(function() {
         InfoPanel.markCollapsed(block, titleText);
         return false;
      });
      blockTitle.append(')');
   };
});

/* Run on API load */
WalkDBMap.ready(function() {
   WalkDBMap.setMap(new google.maps.Map2(document.getElementById('map-panel')));
   WalkDBMap.map.addMapType(G_PHYSICAL_MAP);
});
WalkDBMap.mapAPILoaded = function() {
   WalkDBMap.fireReady();
};
/* Run now */
$(function() {
   $('body').unload(function() {
      GUnload();
   });
   google.load("maps", "2", {'callback': WalkDBMap.mapAPILoaded});
   InfoPanel.initialise();
});