text: /**
   * @namespace WPGMZA
   * @module Map
   * @requires WPGMZA.EventDispatcher
   */
  jQuery(function($) {
  	
  	/**
  	 * Base class for maps. <strong>Please <em>do not</em> call this constructor directly. Always use createInstance rather than instantiating this class directly.</strong> Using createInstance allows this class to be externally extensible.
  	 * @class WPGMZA.Map
  	 * @constructor WPGMZA.Map
  	 * @memberof WPGMZA
  	 * @param {HTMLElement} element to contain map
  	 * @param {object} [options] Options to apply to this map
  	 * @augments WPGMZA.EventDispatcher
  	 */
  	WPGMZA.Map = function(element, options)
  	{
  		var self = this;
  		
  		WPGMZA.assertInstanceOf(this, "Map");
  		
  		WPGMZA.EventDispatcher.call(this);
  		
  		if(!(element instanceof HTMLElement))
  			throw new Error("Argument must be a HTMLElement");
  		
  		this.id = element.getAttribute("data-map-id");
  		if(!/\d+/.test(this.id))
  			throw new Error("Map ID must be an integer");
  		
  		WPGMZA.maps.push(this);
  		this.element = element;
  		this.element.wpgmzaMap = this;
  		
  		this.engineElement = element;
  		
  		this.markers = [];
  		this.polygons = [];
  		this.polylines = [];
  		this.circles = [];
  		
  		this.loadSettings(options);
  		
  		this.shortcodeAttributes = {};
  		if($(this.element).attr("data-shortcode-attributes"))
  			try{
  				this.shortcodeAttributes = JSON.parse($(this.element).attr("data-shortcode-attributes"))
  			}catch(e) {
  				console.warn("Error parsing shortcode attributes");
  			}
  		
  		this.initStoreLocator();
  		
  		this.markerFilter = WPGMZA.MarkerFilter.createInstance(this);
  	}
  	
  	WPGMZA.Map.prototype = Object.create(WPGMZA.EventDispatcher.prototype);
  	WPGMZA.Map.prototype.constructor = WPGMZA.Map;
  	WPGMZA.Map.nightTimeThemeData = [{"elementType":"geometry","stylers":[{"color":"#242f3e"}]},{"elementType":"labels.text.fill","stylers":[{"color":"#746855"}]},{"elementType":"labels.text.stroke","stylers":[{"color":"#242f3e"}]},{"featureType":"administrative.locality","elementType":"labels.text.fill","stylers":[{"color":"#d59563"}]},{"featureType":"landscape","elementType":"geometry.fill","stylers":[{"color":"#575663"}]},{"featureType":"poi","elementType":"labels.text.fill","stylers":[{"color":"#d59563"}]},{"featureType":"poi.park","elementType":"geometry","stylers":[{"color":"#263c3f"}]},{"featureType":"poi.park","elementType":"labels.text.fill","stylers":[{"color":"#6b9a76"}]},{"featureType":"road","elementType":"geometry","stylers":[{"color":"#38414e"}]},{"featureType":"road","elementType":"geometry.stroke","stylers":[{"color":"#212a37"}]},{"featureType":"road","elementType":"labels.text.fill","stylers":[{"color":"#9ca5b3"}]},{"featureType":"road.highway","elementType":"geometry","stylers":[{"color":"#746855"}]},{"featureType":"road.highway","elementType":"geometry.fill","stylers":[{"color":"#80823e"}]},{"featureType":"road.highway","elementType":"geometry.stroke","stylers":[{"color":"#1f2835"}]},{"featureType":"road.highway","elementType":"labels.text.fill","stylers":[{"color":"#f3d19c"}]},{"featureType":"transit","elementType":"geometry","stylers":[{"color":"#2f3948"}]},{"featureType":"transit.station","elementType":"labels.text.fill","stylers":[{"color":"#d59563"}]},{"featureType":"water","elementType":"geometry","stylers":[{"color":"#17263c"}]},{"featureType":"water","elementType":"geometry.fill","stylers":[{"color":"#1b737a"}]},{"featureType":"water","elementType":"labels.text.fill","stylers":[{"color":"#515c6d"}]},{"featureType":"water","elementType":"labels.text.stroke","stylers":[{"color":"#17263c"}]}];
  	
  	/**
  	 * Returns the contructor to be used by createInstance, depending on the selected maps engine.
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @return {function} The appropriate contructor
  	 */
  	WPGMZA.Map.getConstructor = function()
  	{
  		switch(WPGMZA.settings.engine)
  		{
  			case "open-layers":
  				if(WPGMZA.isProVersion())
  					return WPGMZA.OLProMap;
  				
  				return WPGMZA.OLMap;
  				break;
  			
  			default:
  				if(WPGMZA.isProVersion())
  					return WPGMZA.GoogleProMap;
  				
  				return WPGMZA.GoogleMap;
  				break;
  		}
  	}
  
  	/**
  	 * Creates an instance of a map, <strong>please <em>always</em> use this function rather than calling the constructor directly</strong>.
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {HTMLElement} element to contain map
  	 * @param {object} [options] Options to apply to this map
  	 * @return {WPGMZA.Map} An instance of WPGMZA.Map
  	 */
  	WPGMZA.Map.createInstance = function(element, options)
  	{
  		var constructor = WPGMZA.Map.getConstructor();
  		return new constructor(element, options);
  	}
  	
  	/**
  	 * Loads the maps settings and sets some defaults
  	 * @method
  	 * @memberof WPGMZA.Map
  	 */
  	WPGMZA.Map.prototype.loadSettings = function(options)
  	{
  		var settings = new WPGMZA.MapSettings(this.element);
  		var other_settings = settings.other_settings;
  		
  		delete settings.other_settings;
  		
  		/*if(other_settings)
  			for(var key in other_settings)
  				settings[key] = other_settings[key];*/
  			
  		if(options)
  			for(var key in options)
  				settings[key] = options[key];
  			
  		this.settings = settings;
  	}
  	
  	WPGMZA.Map.prototype.initStoreLocator = function()
  	{
  		var storeLocatorElement = $(".wpgmza_sl_main_div");
  		if(storeLocatorElement.length)
  			this.storeLocator = WPGMZA.StoreLocator.createInstance(this, storeLocatorElement[0]);
  	}
  	
  	/**
  	 * This override should automatically dispatch a .wpgmza scoped event on the element
  	 * TODO: Implement
  	 */
  	/*WPGMZA.Map.prototype.trigger = function(event)
  	{
  		
  	}*/
  	
  	/**
  	 * Sets options in bulk on map
  	 * @method
  	 * @memberof WPGMZA.Map
  	 */
  	WPGMZA.Map.prototype.setOptions = function(options)
  	{
  		for(var name in options)
  			this.settings[name] = options[name];
  	}
  	
  	/**
  	 * Gets the distance between two latLngs in kilometers
  	 * NB: Static function
  	 * @return number
  	 */
  	var earthRadiusMeters = 6371;
  	var piTimes360 = Math.PI / 360;
  	
  	function deg2rad(deg) {
  	  return deg * (Math.PI/180)
  	};
  	
  	/**
  	 * This gets the distance in kilometers between two latitude / longitude points
  	 * TODO: Move this to the distance class, or the LatLng class
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {number} lat1 Latitude from the first coordinate pair
  	 * @param {number} lon1 Longitude from the first coordinate pair
  	 * @param {number} lat2 Latitude from the second coordinate pair
  	 * @param {number} lon1 Longitude from the second coordinate pair
  	 * @return {number} The distance between the latitude and longitudes, in kilometers
  	 */
  	WPGMZA.Map.getGeographicDistance = function(lat1, lon1, lat2, lon2)
  	{
  		var dLat = deg2rad(lat2-lat1);
  		var dLon = deg2rad(lon2-lon1); 
  		
  		var a = 
  			Math.sin(dLat/2) * Math.sin(dLat/2) +
  			Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * 
  			Math.sin(dLon/2) * Math.sin(dLon/2); 
  			
  		var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
  		var d = earthRadiusMeters * c; // Distance in km
  		
  		return d;
  	}
  	
  	/**
  	 * Centers the map on the supplied latitude and longitude
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {object|WPGMZA.LatLng} latLng A LatLng literal or an instance of WPGMZA.LatLng
  	 */
  	WPGMZA.Map.prototype.setCenter = function(latLng)
  	{
  		if(!("lat" in latLng && "lng" in latLng))
  			throw new Error("Argument is not an object with lat and lng");
  	}
  	
  	/**
  	 * Sets the dimensions of the map engine element
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {number} width Width as a CSS string
  	 * @param {number} height Height as a CSS string
  	 */
  	WPGMZA.Map.prototype.setDimensions = function(width, height)
  	{
  		$(this.element).css({
  			width: width
  		});
  		
  		$(this.engineElement).css({
  			width: "100%",
  			height: height
  		});
  	}
  	
  	/**
  	 * Adds the specified marker to this map
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {WPGMZA.Marker} marker The marker to add
  	 * @fires markeradded
  	 * @fires WPGMZA.Marker#added
  	 * @throws Argument must be an instance of WPGMZA.Marker
  	 */
  	WPGMZA.Map.prototype.addMarker = function(marker)
  	{
  		if(!(marker instanceof WPGMZA.Marker))
  			throw new Error("Argument must be an instance of WPGMZA.Marker");
  		
  		marker.map = this;
  		marker.parent = this;
  		
  		this.markers.push(marker);
  		this.dispatchEvent({type: "markeradded", marker: marker});
  		marker.dispatchEvent({type: "added"});
  	}
  	
  	/**
  	 * Removes the specified marker from this map
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {WPGMZA.Marker} marker The marker to remove
  	 * @fires markerremoved
  	 * @fires WPGMZA.Marker#removed
  	 * @throws Argument must be an instance of WPGMZA.Marker
  	 * @throws Wrong map error
  	 */
  	WPGMZA.Map.prototype.removeMarker = function(marker)
  	{
  		if(!(marker instanceof WPGMZA.Marker))
  			throw new Error("Argument must be an instance of WPGMZA.Marker");
  		
  		if(marker.map !== this)
  			throw new Error("Wrong map error");
  		
  		if(marker.infoWindow)
  			marker.infoWindow.close();
  		
  		marker.map = null;
  		marker.parent = null;
  		
  		this.markers.splice(this.markers.indexOf(marker), 1);
  		this.dispatchEvent({type: "markerremoved", marker: marker});
  		marker.dispatchEvent({type: "removed"});
  	}
  	
  	/**
  	 * Gets a marker by ID
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {int} id The ID of the marker to get
  	 * @return {WPGMZA.Marker|null} The marker, or null if no marker with the specified ID is found
  	 */
  	WPGMZA.Map.prototype.getMarkerByID = function(id)
  	{
  		for(var i = 0; i < this.markers.length; i++)
  		{
  			if(this.markers[i].id == id)
  				return this.markers[i];
  		}
  		
  		return null;
  	}
  	
  	/**
  	 * Removes a marker by ID
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {int} id The ID of the marker to remove
  	 * @fires markerremoved
  	 * @fires WPGMZA.Marker#removed
  	 */
  	WPGMZA.Map.prototype.removeMarkerByID = function(id)
  	{
  		var marker = this.getMarkerByID(id);
  		
  		if(!marker)
  			return;
  		
  		this.removeMarker(marker);
  	}
  	
  	/**
  	 * Adds the specified polygon to this map
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {WPGMZA.Polygon} polygon The polygon to add
  	 * @fires polygonadded
  	 * @throws Argument must be an instance of WPGMZA.Polygon
  	 */
  	WPGMZA.Map.prototype.addPolygon = function(polygon)
  	{
  		if(!(polygon instanceof WPGMZA.Polygon))
  			throw new Error("Argument must be an instance of WPGMZA.Polygon");
  		
  		polygon.map = this;
  		
  		this.polygons.push(polygon);
  		this.dispatchEvent({type: "polygonadded", polygon: polygon});
  	}
  	
  	/**
  	 * Removes the specified polygon from this map
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {WPGMZA.Polygon} polygon The polygon to remove
  	 * @fires polygonremoved
  	 * @throws Argument must be an instance of WPGMZA.Polygon
  	 * @throws Wrong map error
  	 */
  	WPGMZA.Map.prototype.removePolygon = function(polygon)
  	{
  		if(!(polygon instanceof WPGMZA.Polygon))
  			throw new Error("Argument must be an instance of WPGMZA.Polygon");
  		
  		if(polygon.map !== this)
  			throw new Error("Wrong map error");
  		
  		polygon.map = null;
  		
  		this.polygons.splice(this.polygons.indexOf(polygon), 1);
  		this.dispatchEvent({type: "polygonremoved", polygon: polygon});
  	}
  	
  	/**
  	 * Gets a polygon by ID
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {int} id The ID of the polygon to get
  	 * @return {WPGMZA.Polygon|null} The polygon, or null if no polygon with the specified ID is found
  	 */
  	WPGMZA.Map.prototype.getPolygonByID = function(id)
  	{
  		for(var i = 0; i < this.polygons.length; i++)
  		{
  			if(this.polygons[i].id == id)
  				return this.polygons[i];
  		}
  		
  		return null;
  	}
  	
  	/**
  	 * Removes a polygon by ID
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {int} id The ID of the polygon to remove
  	 */
  	WPGMZA.Map.prototype.removePolygonByID = function(id)
  	{
  		var polygon = this.getPolygonByID(id);
  		
  		if(!polygon)
  			return;
  		
  		this.removePolygon(polygon);
  	}
  	
  	/**
  	 * Gets a polyline by ID
  	 * @return void
  	 */
  	WPGMZA.Map.prototype.getPolylineByID = function(id)
  	{
  		for(var i = 0; i < this.polylines.length; i++)
  		{
  			if(this.polylines[i].id == id)
  				return this.polylines[i];
  		}
  		
  		return null;
  	}
  	
  	/**
  	 * Adds the specified polyline to this map
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {WPGMZA.Polyline} polyline The polyline to add
  	 * @fires polylineadded
  	 * @throws Argument must be an instance of WPGMZA.Polyline
  	 */
  	WPGMZA.Map.prototype.addPolyline = function(polyline)
  	{
  		if(!(polyline instanceof WPGMZA.Polyline))
  			throw new Error("Argument must be an instance of WPGMZA.Polyline");
  		
  		polyline.map = this;
  		
  		this.polylines.push(polyline);
  		this.dispatchEvent({type: "polylineadded", polyline: polyline});
  	}
  	
  	/**
  	 * Removes the specified polyline from this map
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {WPGMZA.Polyline} polyline The polyline to remove
  	 * @fires polylineremoved
  	 * @throws Argument must be an instance of WPGMZA.Polyline
  	 * @throws Wrong map error
  	 */
  	WPGMZA.Map.prototype.removePolyline = function(polyline)
  	{
  		if(!(polyline instanceof WPGMZA.Polyline))
  			throw new Error("Argument must be an instance of WPGMZA.Polyline");
  		
  		if(polyline.map !== this)
  			throw new Error("Wrong map error");
  		
  		polyline.map = null;
  		
  		this.polylines.splice(this.polylines.indexOf(polyline), 1);
  		this.dispatchEvent({type: "polylineremoved", polyline: polyline});
  	}
  	
  	/**
  	 * Gets a polyline by ID
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {int} id The ID of the polyline to get
  	 * @return {WPGMZA.Polyline|null} The polyline, or null if no polyline with the specified ID is found
  	 */
  	WPGMZA.Map.prototype.getPolylineByID = function(id)
  	{
  		for(var i = 0; i < this.polylines.length; i++)
  		{
  			if(this.polylines[i].id == id)
  				return this.polylines[i];
  		}
  		
  		return null;
  	}
  	
  	/**
  	 * Removes a polyline by ID
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {int} id The ID of the polyline to remove
  	 */
  	WPGMZA.Map.prototype.removePolylineByID = function(id)
  	{
  		var polyline = this.getPolylineByID(id);
  		
  		if(!polyline)
  			return;
  		
  		this.removePolyline(polyline);
  	}
  	
  	/**
  	 * Adds the specified circle to this map
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {WPGMZA.Circle} circle The circle to add
  	 * @fires polygonadded
  	 * @throws Argument must be an instance of WPGMZA.Circle
  	 */
  	WPGMZA.Map.prototype.addCircle = function(circle)
  	{
  		if(!(circle instanceof WPGMZA.Circle))
  			throw new Error("Argument must be an instance of WPGMZA.Circle");
  		
  		circle.map = this;
  		
  		this.circles.push(circle);
  		this.dispatchEvent({type: "circleadded", circle: circle});
  	}
  	
  	/**
  	 * Removes the specified circle from this map
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {WPGMZA.Circle} circle The circle to remove
  	 * @fires circleremoved
  	 * @throws Argument must be an instance of WPGMZA.Circle
  	 * @throws Wrong map error
  	 */
  	WPGMZA.Map.prototype.removeCircle = function(circle)
  	{
  		if(!(circle instanceof WPGMZA.Circle))
  			throw new Error("Argument must be an instance of WPGMZA.Circle");
  		
  		if(circle.map !== this)
  			throw new Error("Wrong map error");
  		
  		circle.map = null;
  		
  		this.circles.splice(this.circles.indexOf(circle), 1);
  		this.dispatchEvent({type: "circleremoved", circle: circle});
  	}
  	
  	/**
  	 * Gets a circle by ID
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {int} id The ID of the circle to get
  	 * @return {WPGMZA.Circle|null} The circle, or null if no circle with the specified ID is found
  	 */
  	WPGMZA.Map.prototype.getCircleByID = function(id)
  	{
  		for(var i = 0; i < this.circles.length; i++)
  		{
  			if(this.circles[i].id == id)
  				return this.circles[i];
  		}
  		
  		return null;
  	}
  	
  	/**
  	 * Removes a circle by ID
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {int} id The ID of the circle to remove
  	 */
  	WPGMZA.Map.prototype.removeCircleByID = function(id)
  	{
  		var circle = this.getCircleByID(id);
  		
  		if(!circle)
  			return;
  		
  		this.removeCircle(circle);
  	}
  	
  	/**
  	 * Nudges the map viewport by the given pixel coordinates
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @param {number} x Number of pixels to nudge along the x axis
  	 * @param {number} y Number of pixels to nudge along the y axis
  	 * @throws Invalid coordinates supplied
  	 */
  	WPGMZA.Map.prototype.nudge = function(x, y)
  	{
  		var pixels = this.latLngToPixels(this.getCenter());
  		
  		pixels.x += parseFloat(x);
  		pixels.y += parseFloat(y);
  		
  		if(isNaN(pixels.x) || isNaN(pixels.y))
  			throw new Error("Invalid coordinates supplied");
  		
  		var latLng = this.pixelsToLatLng(pixels);
  		
  		this.setCenter(latLng);
  	}
  	
  	/**
  	 * Called when the window resizes
  	 * @method
  	 * @memberof WPGMZA.Map
  	 */
  	WPGMZA.Map.prototype.onWindowResize = function(event)
  	{
  		
  	}
  	
  	/**
  	 * Called when the engine map div is resized
  	 * @method
  	 * @memberof WPGMZA.Map
  	 */
  	WPGMZA.Map.prototype.onElementResized = function(event)
  	{
  		
  	}
  	
  	/**
  	 * Called when the map viewport bounds change. Fires the legacy bounds_changed event.
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @fires boundschanged
  	 * @fires bounds_changed
  	 */
  	WPGMZA.Map.prototype.onBoundsChanged = function(event)
  	{
  		// Native events
  		this.trigger("boundschanged");
  		
  		// Google / legacy compatibility events
  		this.trigger("bounds_changed");
  	}
  	
  	/**
  	 * Called when the map viewport becomes idle (eg movement done, tiles loaded)
  	 * @method
  	 * @memberof WPGMZA.Map
  	 * @fires idle
  	 */
  	WPGMZA.Map.prototype.onIdle = function(event)
  	{
  		this.trigger("idle");
  	}
  	
  });