# Source: open-layers/ol-map.js

    /**
     * @namespace WPGMZA
     * @module OLMap
     * @requires WPGMZA.Map
     * @pro-requires WPGMZA.ProMap
     */
    (function($) {

    	var Parent;

    	WPGMZA.OLMap = function(element, options)
    	{
    		var self = this;

    		Parent.call(this, element);

    		this.setOptions(options);

    		var viewOptions = this.settings.toOLViewOptions();

    		$(this.element).html("");

    		this.olMap = new ol.Map({
    			target: $(element)[0],
    			layers: [
    				new ol.layer.Tile({
    					source: new ol.source.OSM()
    				})
    			],
    			view: new ol.View(viewOptions)
    		});

    		// TODO: Re-implement using correct setting names
    		// Interactions
    		this.olMap.getInteractions().forEach(function(interaction) {

    			// NB: The true and false values are flipped because these settings represent the "disabled" state when true
    			if(interaction instanceof ol.interaction.DragPan)
    				interaction.setActive( (this.settings.map_draggable ? false : true) );
    			else if(interaction instanceof ol.interaction.DoubleClickZoom)
    				interaction.setActive( (this.settings.map_clickzoom ? false : true) );
    			else if(interaction instanceof ol.interaction.MouseWheelZoom)
    				interaction.setActive( (this.settings.map_scroll ? false : true) );

    		}, this);

    		// Controls
    		this.olMap.getControls().forEach(function(control) {

    			// NB: The true and false values are flipped because these settings represent the "disabled" state when true
    			if(control instanceof ol.control.Zoom && this.settings.map_zoom)
    				this.olMap.removeControl(control);

    		}, this);

    		if(!this.settings.map_full_screen_control)
    			this.olMap.addControl(new ol.control.FullScreen());

    		// Marker layer
    		this.markerLayer = new ol.layer.Vector({
    			source: new ol.source.Vector({
    				features: []
    			})
    		});
    		this.olMap.addLayer(this.markerLayer);

    		// Listen for end of pan so we can wrap longitude if needs be
    		this.olMap.on("moveend", function(event) {
    			self.wrapLongitude();
    			self.dispatchEvent("dragend");
    			self.onIdle();
    		});

    		// Listen for zoom
    		this.olMap.getView().on("change:resolution", function(event) {
    			self.dispatchEvent("zoom_changed");
    			self.dispatchEvent("zoomchanged");
    			self.onIdle();

    			$(self.element).trigger("zoomchanged.wpgmza");
    		});

    		// Listen for bounds changing
    		this.olMap.getView().on("change", function() {
    			// Wrap longitude
    			self.onBoundsChanged();
    		});
    		self.onBoundsChanged();

    		// Store locator center
    		var marker;
    		if(this.storeLocator && (marker = this.storeLocator.centerPointMarker))
    		{
    			this.olMap.addOverlay(marker.overlay);
    			marker.setVisible(false);
    		}

    		// Cycling layer
    		console.log(this.settings);

    		// Right click listener
    		$(this.element).on("click contextmenu", function(event) {

    			var isRight;
    			event = event || window.event;

    			if("which" in event)
    				isRight = event.which == 3;
    			else if("button" in event)
    				isRight = event.button == 2;

    			if(!isRight)
    				return;

    			return self.onRightClick(event);
    		});

    		// Dispatch event
    		if(!WPGMZA.isProVersion())
    		{
    			this.dispatchEvent("created");
    			WPGMZA.events.dispatchEvent({type: "mapcreated", map: this});
    		}
    	}

    	if(WPGMZA.isProVersion())
    		Parent = WPGMZA.ProMap;
    	else
    		Parent = WPGMZA.Map;

    	WPGMZA.OLMap.prototype = Object.create(Parent.prototype);
    	WPGMZA.OLMap.prototype.constructor = WPGMZA.OLMap;

    	WPGMZA.OLMap.prototype.wrapLongitude = function()
    	{
    		var center = this.getCenter();

    		if(center.lng >= -180 && center.lng <= 180)
    			return;

    		center.lng = center.lng - 360 * Math.floor(center.lng / 360);

    		if(center.lng > 180)
    			center.lng -= 360;

    		this.setCenter(center);
    	}

    	WPGMZA.OLMap.prototype.getCenter = function()
    	{
    		var lonLat = ol.proj.toLonLat(
    			this.olMap.getView().getCenter()
    		);
    		return {
    			lat: lonLat[1],
    			lng: lonLat[0]
    		};
    	}

    	WPGMZA.OLMap.prototype.setCenter = function(latLng)
    	{
    		var view = this.olMap.getView();

    		WPGMZA.Map.prototype.setCenter.call(this, latLng);

    		view.setCenter(ol.proj.fromLonLat([
    			latLng.lng,
    			latLng.lat
    		]));

    		this.wrapLongitude();

    		this.onBoundsChanged();
    	}

    	WPGMZA.OLMap.prototype.getBounds = function()
    	{
    		var bounds = this.olMap.getView().calculateExtent(this.olMap.getSize());

    		var topLeft = ol.proj.toLonLat([bounds[0], bounds[1]]);
    		var bottomRight = ol.proj.toLonLat([bounds[2], bounds[3]]);

    		return {
    			topLeft: {
    				lat: topLeft[1],
    				lng: topLeft[0]
    			},
    			bottomRight: {
    				lat: bottomRight[1],
    				lng: bottomRight[0]
    			}
    		};
    	}

    	/**
    	 * Fit to given boundaries
    	 * @return void
    	 */
    	WPGMZA.OLMap.prototype.fitBounds = function(southWest, northEast)
    	{
    		this.olMap.getView().fitExtent(
    			[southWest.lng, southWest.lat, northEast.lng, northEast.lat],
    			this.olMap.getSize()
    		);
    	}

    	WPGMZA.OLMap.prototype.panTo = function(latLng)
    	{
    		var view = this.olMap.getView();
    		view.animate({
    			center: ol.proj.fromLonLat([
    				parseFloat(latLng.lng),
    				parseFloat(latLng.lat),
    			]),
    			duration: 500
    		});
    	}

    	WPGMZA.OLMap.prototype.getZoom = function()
    	{
    		return Math.round( this.olMap.getView().getZoom() ) + 1;
    	}

    	WPGMZA.OLMap.prototype.setZoom = function(value)
    	{
    		this.olMap.getView().setZoom(value);
    	}

    	WPGMZA.OLMap.prototype.getMinZoom = function()
    	{
    		return this.olMap.getView().getMinZoom();
    	}

    	WPGMZA.OLMap.prototype.setMinZoom = function(value)
    	{
    		this.olMap.getView().setMinZoom(value);
    	}

    	WPGMZA.OLMap.prototype.getMaxZoom = function()
    	{
    		return this.olMap.getView().getMaxZoom();
    	}

    	WPGMZA.OLMap.prototype.setMaxZoom = function(value)
    	{
    		this.olMap.getView().setMaxZoom(value);
    	}

    	WPGMZA.OLMap.prototype.setOptions = function(options)
    	{
    		Parent.prototype.setOptions.call(this, options);

    		if(!this.olMap)
    			return;

    		this.olMap.getView().setProperties( this.settings.toOLViewOptions() );
    	}

    	/**
    	 * TODO: Consider moving all these functions to their respective classes, same on google map (DO IT!!! It's very misleading having them here)
    	 */
    	WPGMZA.OLMap.prototype.addMarker = function(marker)
    	{
    		this.olMap.addOverlay(marker.overlay);

    		Parent.prototype.addMarker.call(this, marker);
    	}

    	WPGMZA.OLMap.prototype.removeMarker = function(marker)
    	{
    		this.olMap.removeOverlay(marker.overlay);

    		Parent.prototype.removeMarker.call(this, marker);
    	}

    	WPGMZA.OLMap.prototype.addPolygon = function(polygon)
    	{
    		this.olMap.addLayer(polygon.layer);

    		Parent.prototype.addPolygon.call(this, polygon);
    	}

    	WPGMZA.OLMap.prototype.removePolygon = function(polygon)
    	{
    		this.olMap.removeLayer(polygon.layer);

    		Parent.prototype.removePolygon.call(this, polygon);
    	}

    	WPGMZA.OLMap.prototype.addPolyline = function(polyline)
    	{
    		this.olMap.addLayer(polyline.layer);

    		Parent.prototype.addPolyline.call(this, polyline);
    	}

    	WPGMZA.OLMap.prototype.removePolyline = function(polyline)
    	{
    		this.olMap.removeLayer(polyline.layer);

    		Parent.prototype.removePolyline.call(this, polyline);
    	}

    	WPGMZA.OLMap.prototype.addCircle = function(circle)
    	{
    		this.olMap.addLayer(circle.layer);

    		Parent.prototype.addCircle.call(this, circle);
    	}

    	WPGMZA.OLMap.prototype.removeCircle = function(circle)
    	{
    		this.olMap.removeLayer(circle.layer);

    		Parent.prototype.removeCircle.call(this, circle);
    	}

    	WPGMZA.OLMap.prototype.pixelsToLatLng = function(x, y)
    	{
    		if(y == undefined)
    		{
    			if("x" in x && "y" in x)
    			{
    				y = x.y;
    				x = x.x;
    			}
    			else
    				console.warn("Y coordinate undefined in pixelsToLatLng (did you mean to pass 2 arguments?)");
    		}

    		var coord = this.olMap.getCoordinateFromPixel([x, y]);

    		if(!coord)
    			return {
    				x: null,
    				y: null
    			};

    		var lonLat = ol.proj.toLonLat(coord);
    		return {
    			lat: lonLat[1],
    			lng: lonLat[0]
    		};
    	}

    	WPGMZA.OLMap.prototype.latLngToPixels = function(latLng)
    	{
    		var coord = ol.proj.fromLonLat([latLng.lng, latLng.lat]);
    		var pixel = this.olMap.getPixelFromCoordinate(coord);

    		if(!pixel)
    			return {
    				x: null,
    				y: null
    			};

    		return {
    			x: pixel[0],
    			y: pixel[1]
    		};
    	}

    	WPGMZA.OLMap.prototype.enableBicycleLayer = function(value)
    	{
    		if(value)
    		{
    			if(!this.bicycleLayer)
    				this.bicycleLayer = new ol.layer.Tile({
    					source: new ol.source.OSM({
    						url: "http://{a-c}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png"
    					})
    				});

    			this.olMap.addLayer(this.bicycleLayer);
    		}
    		else
    		{
    			if(!this.bicycleLayer)
    				return;

    			this.olMap.removeLayer(this.bicycleLayer);
    		}
    	}

    	WPGMZA.OLMap.prototype.onElementResized = function(event)
    	{
    		this.olMap.updateSize();
    	}

    	WPGMZA.OLMap.prototype.onRightClick = function(event)
    	{
    		if($(event.target).closest(".ol-marker, .wpgmza_modern_infowindow, .wpgmza-modern-store-locator").length)
    			return true;

    		var parentOffset = $(this.element).offset();
    		var relX = event.pageX - parentOffset.left;
    		var relY = event.pageY - parentOffset.top;
    		var latLng = this.pixelsToLatLng(relX, relY);

    		this.trigger({type: "rightclick", latLng: latLng});
    		$(this.element).trigger("rightclick.wpgmza");

    		event.preventDefault();
    		return false;
    	}

    })(jQuery);