﻿/// <reference path="~/js/jquery-1.3.2.js" />

var m_objMap;

if (!m_objMap) m_objMap = {};

// The main object that holds the maps
m_objMap.MapObjects = {};


/**
* Creates a new map on the passed element with the defined options.  Creates a global object that contains the map.
* @method
* @namespace Mapifies.MapObjects
* @id Mapifies.MapObjects.Set
* @alias Mapifies.MapObjects.Set
* @param {jQuery} element The element that contains the map.
* @param {Object} options An object that contains the options.
* @return {Object} The object that contains the map.
*/
m_objMap.MapObjects.Set = function(element, options) {
  var mapName = jQuery(element).attr('id');
  var thisMap = new GMap2(element);
  m_objMap.MapObjects[mapName] = thisMap;
  m_objMap.MapObjects[mapName].Options = options;
  return m_objMap.MapObjects[mapName];
};

/**
* Adds additional objects and functions to an existing MapObject
* @method
* @namespace Mapifies.MapObjects
* @id Mapifies.MapObjects.Append
* @alias Mapifies.MapObjects.Append
* @param {jQuery} element The element that contains the map
* @param {Object} description The name of the object to create
* @param {Object} appending The object or function to append
*/
m_objMap.MapObjects.Append = function(element, description, appending) {
  var mapName = jQuery(element).attr('id');
  m_objMap.MapObjects[mapName][description] = appending;
};


/**
* Returns the current map object for the passed element
* @method
* @namespace Mapifies.MapObjects
* @id Mapifies.MapObjects.Get
* @alias Mapifies.MapObjects.Get
* @param {jQuery} element The element that contains the map.
* @return {Object} Mapifies The Mapifies object that contains the map.
*/
m_objMap.MapObjects.Get = function(element) {
  return m_objMap.MapObjects[jQuery(element).attr('id')];
};


/**
* Default options for Initialise
* @method
* @namespace m_objMap.Initialise
* @id m_objMap.Initialise.defaults
* @alias m_objMap.Initialise.defaults
* @param {String} language The locale language for the map
* @param {String} mapType The type of map to create.  Options are 'map' (default), 'sat' and 'hybrid'.
* @param {Object} mapCenter An array that contains the Lat/Lng coordinates of the map center.
* @param {Number} mapZoom The initial zoom level of the map.
* @param {String} mapControl The option for the map control.  The options are 'small' (default), 'large' or 'none'
* @param {Boolean} mapEnableType Defines if the buttons for map type are shown.  Default false.
* @param {Boolean} mapEnableOverview Defines if the map overview is shown.  Default false.
* @param {Boolean} mapEnableDragging Defines if the map is draggable or not.  Default true.
* @param {Boolean} mapEnableInfoWindows Defines if info windows are shown on the map or not.  Default true.
* @param {Boolean} mapEnableDoubleClickZoom Defines if double clicking zooms the map.  Default false.
* @param {Boolean} mapEnableSmoothZoom Defines if smooth scrolling is enabled.  Default false.
* @param {Boolean} mapEnableGoogleBar Defines if the google map search tool is enabled.  Default false.
* @param {Boolean} mapEnableScaleControl Defines if the scale bar is shown.  Default false.
* @param {Boolean} mapShowjMapsIcon Defines if the jMaps icon is shown.  Default true.
* @param {Boolean} debugMode Defines if the map object created is returned to the Firebug console.  Default false.
* @return {Object} The options for SearchAddress
*/

m_objMap.Initialise = function(element, options, callback) {
  function defaults() {
    return {
      // Initial type of map to display
      'language': 'en',
      // Options: "map", "sat", "hybrid"
      'mapType': 'map',
      // Initial map center
      'mapCenter': [55.958858, -3.162302],
      // Initial zoom level
      'mapZoom': 12,
      // Initial map control size
      // Options: "large", "small", "none"
      'mapControl': 'small',
      // Initialise type of map control
      'mapEnableType': false,
      // Initialise small map overview
      'mapEnableOverview': false,
      // Enable map dragging when left button held down
      'mapEnableDragging': true,
      // Enable map info windows
      'mapEnableInfoWindows': true,
      // Enable double click zooming
      'mapEnableDoubleClickZoom': false,
      // Enable zooming with scroll wheel
      'mapEnableScrollZoom': true,
      // Enable smooth zoom
      'mapEnableSmoothZoom': false,
      // Enable Google Bar
      'mapEnableGoogleBar': false,
      // Enables scale bar
      'mapEnableScaleControl': false,
      // Enable the m_objMap icon
      'mapShowjMapsIcon': true,
      //Debug Mode
      'debugMode': false
    };
  };
  options = jQuery.extend(defaults(), options);

  if (GBrowserIsCompatible()) {

    var thisMap = m_objMap.MapObjects.Set(element, options);
    var mapType = m_objMap.GetMapType(options.mapType);
    thisMap.setCenter(new GLatLng(options.mapCenter[0], options.mapCenter[1]), options.mapZoom, mapType);

    //    if (options.mapShowjMapsIcon) {
    //      m_objMap.AddScreenOverlay(element,
    //				{
    //				  'imageUrl': 'http://hg.digitalspaghetti.me.uk/jmaps/raw-file/3228fade0b3c/docs/images/jmaps-mapicon.png',
    //				  'screenXY': [70, 10],
    //				  'overlayXY': [0, 0],
    //				  'size': [42, 25]
    //				}
    //			);
    //    }

    // Attach a controller to the map view
    // Will attach a large or small.  If any other value passed (i.e. "none") it is ignored
    var topRight;
    switch (options.mapControl)
    {
      case "small":
        topRight = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(10, 10));
        thisMap.addControl(new GSmallMapControl(), topRight);
        break;
      case "large":
        topRight = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(10, 10));
        thisMap.addControl(new GLargeMapControl(), topRight);
        break;
      case "large3d":
        topRight = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(10, 25));
        thisMap.addControl(new GLargeMapControl3D(), topRight);
        break;
    };
    // Type of map Control (Map,Sat,Hyb)
    if (options.mapEnableType)
      thisMap.addControl(new GMapTypeControl()); // Off by default
    // Show the small overview map
    if (options.mapEnableOverview)
      thisMap.addControl(new GOverviewMapControl()); // Off by default
    // GMap2 Functions (in order of the docs for clarity)
    // Enable a mouse-dragable map
    if (!options.mapEnableDragging)
      thisMap.disableDragging(); // On by default
    // Enable Info Windows
    if (!options.mapEnableInfoWindows)
      thisMap.disableInfoWindow(); // On by default
    // Enable double click zoom on the map
    if (options.mapEnableDoubleClickZoom)
      thisMap.enableDoubleClickZoom(); // On by default
    // Enable scrollwheel on the map
    if (options.mapEnableScrollZoom)
      thisMap.enableScrollWheelZoom(); //Off by default
    // Enable smooth zooming
    if (options.mapEnableSmoothZoom)
      thisMap.enableContinuousZoom(); // Off by default
    // Enable Google Bar
    if (options.mapEnableGoogleBar)
      thisMap.enableGoogleBar(); //Off by default
    // Enables Scale bar
    if (options.mapEnableScaleControl)
      thisMap.addControl(new GScaleControl());

    if (options.debugMode)
      console.log(m_objMap);

    if (typeof callback == 'function')
      return callback(thisMap, element, options);
  } else {
    jQuery(element).text('Your browser does not support Google Maps.');
    return false;
  }
  return;
};


/**
* This function allows you to add markers to the map with several options
* @method
* @namespace m_objMap
* @id m_objMap.AddMarker
* @alias m_objMap.AddMarker
* @param {jQuery} element The element to initialise the map on.
* @param {Object} options The object that contains the options.
* @param {Function} callback The callback function to pass out after initialising the map.
* @return {Function} callback The callback option with the marker object and options.
*/
m_objMap.AddMarker = function(element, options, callback)
{
  /**
  * Default options for AddGroundOverlay
  * @method
  * @namespace m_objMap.AddGroundOverlay
  * @id m_objMap.AddGroundOverlay.defaults
  * @alias m_objMap.AddGroundOverlay.defaults
  * @param {Object} pointLatLng The Lat/Lng coordinates of the marker.
  * @param {String} pointHTML The HTML to appear in the markers info window.
  * @param {String} pointOpenHTMLEvent The javascript event type to open the marker info window.  Default is 'click'.
  * @param {Boolean} pointIsDraggable Defines if the point is draggable by the end user.  Default false.
  * @param {Boolean} pointIsRemovable Defines if the point can be removed by the user.  Default false.
  * @param {Boolean} pointRemoveEvent The event type to remove a marker.  Default 'dblclick'.
  * @param {Number} pointMinZoom The minimum zoom level to display the marker if using a marker manager.
  * @param {Number} pointMaxZoom The maximum zoom level to display the marker if using a marker manager.
  * @param {GIcon} pointIcon A GIcon to display instead of the standard marker graphic.
  * @param {Boolean} centerMap Automatically center the map on the new marker.  Default false.
  * @param {String} centerMoveMethod The method in which to move to the marker.  Options are 'normal' (default) and 'pan'.  Added r64
  * @return {Object} The options for AddGroundOverlay
  */
  function defaults()
  {
    var values = {
      'pointLatLng': undefined,
      'pointHTML': undefined,
      'pointOpenHTMLEvent': 'click',
      'pointIsDraggable': false,
      'pointIsRemovable': false,
      'pointRemoveEvent': 'dblclick',
      'pointMinZoom': 4,
      'pointMaxZoom': 17,
      'pointIcon': undefined,
      'centerMap': false,
      'centerMoveMethod': 'normal',
      'markerID': undefined,
      'pointOnClick': undefined
    };
    return values;
  };
  var thisMap = m_objMap.MapObjects.Get(element);
  options = jQuery.extend({}, defaults(), options);

  var markerOptions = {}

  if (typeof options.pointIcon == 'object')
    jQuery.extend(markerOptions, { 'icon': options.pointIcon });

  if (options.pointIsDraggable)
    jQuery.extend(markerOptions, { 'draggable': options.pointIsDraggable });

  if (options.centerMap)
  {
    switch (options.centerMoveMethod)
    {
      case 'normal':
        thisMap.setCenter(new GLatLng(options.pointLatLng[0], options.pointLatLng[1]));
        break;
      case 'pan':
        thisMap.panTo(new GLatLng(options.pointLatLng[0], options.pointLatLng[1]));
        break;
    }
  }

  // Create marker, optional parameter to make it draggable
  var marker = new GMarker(new GLatLng(options.pointLatLng[0], options.pointLatLng[1]), markerOptions);

  // If an ID has been provided
  if (options.markerID)
    marker.id = options.markerID;

  // If it has HTML to pass in, add an event listner for a click (and set a custom made property for the html)
  if (options.pointHTML)
  {
    marker.infohtml = options.pointHTML;
    GEvent.addListener(marker, options.pointOpenHTMLEvent, function()
    {
      marker.openInfoWindowHtml(marker.infohtml, { maxContent: options.pointMaxContent, maxTitle: options.pointMaxTitle });
    });
  }
  else
  {
    if (options.pointOnClick != undefined)
    {
      GEvent.addListener(marker, 'click', function()
      {
        options.pointOnClick(marker);
        //marker.openInfoWindowHtml(marker.infohtml, { maxContent: options.pointMaxContent, maxTitle: options.pointMaxTitle });
      });
    }
  }

  // If it is removable, add dblclick event
  if (options.pointIsRemovable)
    GEvent.addListener(marker, options.pointRemoveEvent, function()
    {
      thisMap.removeOverlay(marker);
    });

  // If the marker manager exists, add it
  if (thisMap.MarkerManager)
  {
    thisMap.MarkerManager.addMarker(marker, options.pointMinZoom, options.pointMaxZoom);
  } else
  {
    // Direct rendering to map
    thisMap.addOverlay(marker);
  }

  if (typeof callback == 'function') return callback(marker, options);
};


/**
* This function allows you to remove markers from the map
* @method
* @namespace m_objMap
* @id m_objMap.RemoveMarker
* @alias m_objMap.RemoveMarker
* @param {jQuery} element The element to initialise the map on.
* @param {GMarker} options The marker to be removed
* @param {Function} callback The callback function to pass out after initialising the map.
* @return {Function} callback The callback option with the marker object.
*/
m_objMap.RemoveMarker = function(element, marker, callback) {
  var thisMap = m_objMap.MapObjects.Get(element);
  thisMap.removeOverlay(marker);
  if (typeof callback === 'function') return callback(marker);
  return;
};

// Clear all markers (=overlays)
m_objMap.RemoveAllMarkers = function(element, callback) {
  var thisMap = m_objMap.MapObjects.Get(element);
  thisMap.clearOverlays();
  if (typeof callback === 'function') return callback();
  return;
};

m_objMap.OpenMarker = function(element, markerID, callback) {
  var thisMap = m_objMap.MapObjects.Get(element);
  for (i = 0; i < thisMap.overlays.length; i++) {
    if (thisMap.overlays[i].id) {
      if (thisMap.overlays[i].id == markerID) {
        thisMap.overlays[i].openInfoWindowHtml(thisMap.overlays[i].infohtml, { maxContent: options.pointMaxContent, maxTitle: options.pointMaxTitle });
      }
    }
  }
}

/**
* An internal function to get the google maptype constant
* @method
* @namespace Mapifies
* @id Mapifies.GetMapType
* @alias Mapifies.GetMapType
* @param {String} mapType The string of the map type.
* @return {String} mapType The Google constant for a maptype.
*/
m_objMap.GetMapType = function(mapType) {
  // Lets set our map type based on the options
  switch (mapType) {
    case 'map': // Normal Map
      mapType = G_NORMAL_MAP;
      break;
    case 'sat': // Satallite Imagery
      mapType = G_SATELLITE_MAP;
      break;
    case 'hybrid': //Hybrid Map
      mapType = G_HYBRID_MAP;
      break;
  };
  return mapType;
};

/**
* A helper function to create a google GIcon
* @method
* @namespace m_objMap
* @id m_objMap.createIcon
* @alias m_objMap.createIcon
* @param {Object} options The options to create the icon
* @return {GIcon} A GIcon object
*/
m_objMap.createIcon = function(options) {
  /**
  * Default options for createIcon
  * @method
  * @namespace m_objMap.createIcon
  * @id m_objMap.createIcon.defaults
  * @alias m_objMap.createIcon.defaults
  * @param {String} iconImage The foreground image URL of the icon.
  * @param {String} iconShadow The shadow image URL of the icon.
  * @param {GSize} iconSize The pixel size of the foreground image of the icon.
  * @param {GSize} iconShadowSize The pixel size of the shadow image.
  * @param {GPoint} iconAnchor The pixel coordinate relative to the top left corner of the icon image at which this icon is anchored to the map.
  * @param {GPoint} iconInfoWindowAnchor The pixel coordinate relative to the top left corner of the icon image at which the info window is anchored to this icon.
  * @param {String} iconPrintImage The URL of the foreground icon image used for printed maps. It must be the same size as the main icon image given by image.
  * @param {String} iconMozPrintImage The URL of the foreground icon image used for printed maps in Firefox/Mozilla. It must be the same size as the main icon image given by image.
  * @param {String} iconPrintShadow The URL of the shadow image used for printed maps. It should be a GIF image since most browsers cannot print PNG images.
  * @param {String} iconTransparent The URL of a virtually transparent version of the foreground icon image used to capture click events in Internet Explorer. This image should be a 24-bit PNG version of the main icon image with 1% opacity, but the same shape and size as the main icon.
  * @return {Object} The options for createIcon
  */
  function defaults() {
    return {
      'iconImage': undefined,
      'iconShadow': undefined,
      'iconSize': undefined,
      'iconShadowSize': undefined,
      'iconAnchor': undefined,
      'iconInfoWindowAnchor': undefined,
      'iconPrintImage': undefined,
      'iconMozPrintImage': undefined,
      'iconPrintShadow': undefined,
      'iconTransparent': undefined
    };
  };

  options = jQuery.extend(defaults(), options);
  var icon = new GIcon(G_DEFAULT_ICON);

  if (options.iconImage)
    icon.image = options.iconImage;
  if (options.iconShadow)
    icon.shadow = options.iconShadow;
  if (options.iconSize)
    icon.iconSize = options.iconSize;
  if (options.iconShadowSize)
    icon.shadowSize = options.iconShadowSize;
  if (options.iconAnchor)
    icon.iconAnchor = options.iconAnchor;
  if (options.iconInfoWindowAnchor)
    icon.infoWindowAnchor = options.iconInfoWindowAnchor;
  return icon;
};

(function($) {
  $.fn.jmap = function(method, options, callback) {
    return this.each(function() {
      if (method == 'init' && typeof options == 'undefined') {
        new m_objMap.Initialise(this, {}, null);
      } else if (method == 'init' && typeof options == 'object') {
        new m_objMap.Initialise(this, options, callback);
      } else if (method == 'init' && typeof options == 'function') {
        new m_objMap.Initialise(this, {}, options);
      } else if (typeof method == 'object' || method == null) {
        new m_objMap.Initialise(this, method, options);
      } else {
        try {
          new m_objMap[method](this, options, callback);
        } catch (err) {
          throw Error('iGMap Function Does Not Exist');
        }
      }
    });
  }
})(jQuery);


