/*
	Created by Michael Schuijff <michael@reglobe.nl>
	Copyright Lost Images, The Netherlands
	
	For more information, visit www.michaelschuijff.nl
*/

function geoMap (values) {
	values = values || {};
	
	let geoMap = this;
	
	let container = createElement('div', 'map-outer');
	
	if (values.hidden) {
		container.className += ' hidden';
	}
	
	let inner = createElement('div', 'map-inner');
	
	container.append(inner);
	
	Object.assign(geoMap, {
		container: container, inner: inner,
		hidden: !!values.hidden
	});

	if (typeof values.latitude == 'number' || typeof values.latitude == 'string') {
		Object.assign(geoMap, {
			latitude: +values.latitude, longitude: +values.longitude
		});
	} else {
		Object.assign(geoMap, {
			latitude: +options.get('latitude', config.latitude), longitude: +options.get('longitude', config.longitude)
		});
	}
	
	let gps = !!values.gps && (values.latitude === null || values.latitude === undefined);
	
	geoMap.hide = function () {
		geoMap.hidden = true;
		container.classList.add('hidden');
	}
	
	geoMap.unhide = function () {
		geoMap.hidden = false;
		container.classList.remove('hidden');
		
		if (map) {
			map.updateSize();
		}
		
		if (gps) {
			navigator.geolocation.getCurrentPosition((e) => {
				options.set('geolocation', 'enabled');
				geoMap.setLocation(e.coords.latitude, e.coords.longitude);
			}, null, {
				timeout: 15000, enableHighAccuracy: true
			});
			
			gps = false;
		}
	}

	let timer;
	
	geoMap.setLocation = function (latitude, longitude) {
		clearTimeout(timer);
		
		if (isNaN(latitude) || isNaN(longitude) || typeof latitude != 'number' || typeof longitude != 'number') {
			return false;
		}
		
		if (Math.abs(latitude) > 90 || Math.abs(longitude) > 180) {
			return false;
		}
		
		Object.assign(geoMap, {
			latitude: latitude, longitude: longitude
		});
		
		if (view) {
			let coords = ol.proj.fromLonLat([longitude, latitude]);
			view.setCenter(coords);
		}

		timer = setTimeout(() => {
			options.set('latitude', latitude);
			options.set('longitude', longitude);
		}, 100);
		
		if (values.change) {
			values.change(latitude, longitude);
		}
	}
	
	geoMap.resize = function () {
		if (map) {
			map.updateSize();
		}
	}
	
	geoMap.destroy = function () {
		if (map) {
			map.setTarget(null);
		}
	}
	
	let map, view;
	
	preload('ol/marker.png', (url, image) => {
		loadScript('ol/ol.js', () => {
			let source = new ol.source.OSM;
			
			if ((window.devicePixelRatio || 1) > 1) {
				source = new ol.source.XYZ({
					url: 'https://tile.osmand.net/hd/{z}/{x}/{y}.png',
					crossOrigin: null,
					tilePixelRatio: window.devicePixelRatio,
					attributions: ol.source.OSM.ATTRIBUTION,
					attributionsCollapsible: false
				});
			}
			
			let layers = [new ol.layer.Tile({ source: source })];
			
			let zoom = values.zoom || 8;
			
			if (values.gps) {
				zoom = 12;
			}
			
			view = new ol.View({
				center: ol.proj.fromLonLat([geoMap.longitude, geoMap.latitude]), zoom: zoom, minZoom: 3, maxZoom: 17
			});
		
			let interactions = [];
			
			if (values.movable) {
				interactions = ol.interaction.defaults({
					altShiftDragRotate: false, pinchRotate: false
				});
			}
			
			let controls = ol.control.defaults({
				rotate: false, zoom: !!values.movable
			});

			map = new ol.Map({
				target: inner, layers: layers, view: view, interactions: interactions, controls: controls
			});
			
			if (values.marker) {
				let canvas, ctx;
				
				map.on('postrender', () => {
					if (!canvas) {
						canvas = inner.querySelector('canvas');
						
						if (!canvas) {
							return;
						}
						
						ctx = canvas.getContext('2d');
					}
					
					const scale = .5 * window.devicePixelRatio;
					
					let left = (canvas.width - image.width * scale) / 2
						, top	 =  canvas.height / 2 - image.height * scale;
						
					let width	 = image.width  * scale
						, height = image.height * scale;
					
					ctx.drawImage(image, left, top, width, height);
				});
			}
			
			if (values.movable) {
				map.on('moveend', () => {
					let coords = ol.proj.toLonLat(map.getView().getCenter());
					
					let latitude = +coords[1].toFixed(5), longitude = +coords[0].toFixed(5);
					
					Object.assign(geoMap, {
						latitude: latitude, longitude: longitude
					});
					
					clearTimeout(timer);

					timer = setTimeout(() => {
						options.set('latitude', latitude);
						options.set('longitude', longitude);
					}, 100);

					if (values.change) {
						values.change(latitude, longitude);
					}
				});
			}
			
			if (values.click) {
				map.on('click', values.click);
			}
			
			if (gps && !values.hidden) {
				navigator.geolocation.getCurrentPosition((e) => {
					options.set('geolocation', 'enabled');
					geoMap.setLocation(e.coords.latitude, e.coords.longitude);
				}, null, {
					timeout: 15000, enableHighAccuracy: true
				});
				
				gps = false;
			}
			
			Object.assign(geoMap, {
				map: map, view: view
			});
		});
	});
	
	loadCSS('ol/ol.css');
}
