/**

 * @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: [

				this.getTileLayer()

			],

			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.wpgmza_settings_map_draggable == "yes" ? false : true) );

			else if(interaction instanceof ol.interaction.DoubleClickZoom)

				interaction.setActive( (this.settings.wpgmza_settings_map_clickzoom ? false : true) );

			else if(interaction instanceof ol.interaction.MouseWheelZoom)

				interaction.setActive( (this.settings.wpgmza_settings_map_scroll == "yes" ? 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 && WPGMZA.settings.wpgmza_settings_map_zoom == "yes")

				this.olMap.removeControl(control);

			

		}, this);

		

		if(WPGMZA.settings.wpgmza_settings_map_full_screen_control != "yes")

			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();

		});

		

		// 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);

		}

		

		// Right click listener

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

			

			var isRight;

			event = event || window.event;

			

			var latLng = self.pixelsToLatLng(event.offsetX, event.offsetY);

			

			if("which" in event)

				isRight = event.which == 3;

			else if("button" in event)

				isRight = event.button == 2;

			

			if(event.which == 1 || event.button == 1)

			{

				// Left

				self.trigger({

					type: "click",

					latLng: latLng

				});

				return;

			}

			

			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.getTileLayer = function()

	{

		return new ol.layer.Tile({

			source: new ol.source.OSM()

		});

	}

	

	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});

		

		// Legacy event compatibility

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

		

		// Prevent menu

		event.preventDefault();

		return false;

	}

	

})(jQuery);