/**
 * Base RunTrackr Map.
 *
 * This defines the base map type used for all maps across the site.  In
 * general, this class or its children should only be instantiated once
 * (singleton pattern) though in certain situations, it may be necessary to
 * have more than one map present.
 *
 * @class Map
 * @namespace runtrackr
 * @requires runtrackr.js, Google Maps, jQuery >= 1.2.2
 */
if (typeof(runtrackr) == 'undefined')
  runtrackr = {};

/**
 * Constructor must take the id of the element to use as the map, along with
 * optional parameters specifying the initial map state.
 *
 * @param Object options an object containing the following properties:
 *        mapId: (String) the id of the DOM element to use as the map.
 *        centerPoint: (GLatLng) the optional initial location to center on.
 *        initialZoom: (Number) the optional initial zoom level of the map.
 */
runtrackr.Map = function(options)
{
  // Do not instantiate map if mapId not supplied.  This check is done
  // because for prototypal inheritance, a no-arg constructor is used.
  if (!options || !options.mapId)
  {
    return;
  }

  // TODO: Consider passing the ENTIRE options object into the GMap2 constructor;
  // this will allow individual callers to OVERRIDE any of the available options
  // instead of having to manually copy each one. (Must make sure keys do not
  // overlap!)

  // These arguments are optional and may not have been supplied to the
  // constructor.
  if (!options.centerPoint)
  {
    // At the default settings, map is roughly centered on the US and includes
    // most of North America.
    options.centerPoint = new GLatLng(42.5, -95.1419);
  }
  if (!options.initialZoom)
  {
    options.initialZoom = 3;
  }
  if (!options.draggableCursor)
  {
    // Will result in default cursor.
    options.draggableCursor = '';
  }

  // TODO: Is this properly setting the property on the prototype, or is it
  // creating a local value?
  // http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Property_Inheritance_Revisited:Local_versus_Inherited_Values

  // Initialize map and setup options.
  this._map = new GMap2(document.getElementById(options.mapId), {draggableCursor: options.draggableCursor});
  this._map.setCenter(options.centerPoint, options.initialZoom);
  this._map.addControl(new GLargeMapControl());
  this._map.addMapType(G_PHYSICAL_MAP);
  this._map.addControl(new GHierarchicalMapTypeControl());
  this._map.addControl(new GScaleControl());
  this._map.addControl(new GOverviewMapControl());
  this._map.enableScrollWheelZoom();
  this._map.enableContinuousZoom();
}

/*--- Public constants ---*/

/**
 * Error codes passed into callbacks.
 */
runtrackr.Map.ERROR =
{
  LOCATION_NOT_FOUND: 1,
  LOCATION_NOT_ACCURATE: 2,
  LOCATION_MULTIPLE_MATCHES: 3
}

/**
 * Google Maps Geocoder Accuracy levels.
 * Ref: http://code.google.com/apis/maps/documentation/reference.html#GGeoAddressAccuracy
 * `Town` label changed to `Locality`
 */
runtrackr.Map.GGeoAddressAccuracy =
{
  UNKNOWN_LOCATION: 0,
  COUNTRY: 1,
  REGION: 2,
  SUB_REGION: 3,
  LOCALITY: 4,
  POST_CODE: 5,
  STREET: 6,
  INTERSECTION: 7,
  ADDRESS: 8,
  PREMISE: 9
};

/**
 * Default zoom levels.
 */
runtrackr.Map.ZOOM_DEFAULTS =
{
  ROUTE: 13,

  LOCALITY: 13,
  STREET: 15,
  ADDRESS: 16,

  // TODO: Adjust this for optimal...
  // eg: bikers going long/straight distances might need a lower zoom level.
  MIN_ADDING_POINTS: 11
};

/*--- Private variables ---*/

/**
 * The map. (Google Maps)
 *
 * @type GMap2
 */
runtrackr.Map.prototype._map;

/**
 * Geocoder to resolve addresses/locations to lat/lng co-ordinates.
 *
 * @type GClientGeocoder
 */
runtrackr.Map.prototype._geocoder = new GClientGeocoder();

/**
 * Store the list of markers that are on the map.
 *
 * @type Array<GMarker>
 */
runtrackr.Map.prototype._markers = [];

/*--- Methods ---*/

/**
 * Returns the map.
 *
 * @return GMap2 the map of this object.
 */
runtrackr.Map.prototype.getMap = function()
{
  return this._map;
}

/**
 * Returns the list of markers currently attached to the map.
 *
 * @return Array the list of markers attached to the map.
 */
runtrackr.Map.prototype.getMarkers = function()
{
  return this._markers;
}

// TODO: Fix to see if this reduces browser memory leaks without having to
// explicitly set the attribute in HTML.
jQuery(document).ready(function()
{
  jQuery('body').attr('onunload', 'GUnload()');

  // TODO: Figure out how to prevent `Javascript Disabled` warning message from
  // flashing intermittently.
  // Display content if Google Maps is supported.
  if (GBrowserIsCompatible())
  {
    jQuery('#content').removeClass('javascript-hide');
    jQuery('#javascript-disabled').hide();
  }
});