/**
 * This file implements a significant portion of the otherwise Clean implementation of the leaflet editor. The
 * purpose of this separation is to prevent the many context switches that otherwise take place.
 *
 * Two main functions will dominate this file, the first is leafletCreateMarkers, a function called when new markers are
 * received from the server.
 * The second is the leaflerPixiDraw function, called when the PixiOverlay layer is drawn.
 */
function leafletMarkerOnMouseOver(e) {
	if (e.currentTarget._title != null) {
		const x = e.data.originalEvent.clientX + 10;
		const y = e.data.originalEvent.clientY + 10;

		const div = document.createElement("div");

		div.className  = "marker-tooltip";
		div.innerHTML  = e.currentTarget._title;
		div.style.left = x.toString() + "px";
		div.style.top  = y.toString() + "px";

		document.body.appendChild(div);
	}
}

function leafletMarkerOnMouseOut(e) {
	let tooltips = document.body.getElementsByClassName("marker-tooltip");
	for (var i = tooltips.length - 1; i >= 0; i--) {
		document.body.removeChild(tooltips[i]);
	}
}

function leafletCreateMarker(me, map, taskId, editorId, marker) {
	const iconId = marker.icon;
	const sprite = new PIXI.Sprite(me.textures[marker.icon]);
	const coords = map.project(marker.position);

	// Set all sprite properties
	sprite.markerId =    marker.markerId;
	sprite.angle =       (marker.rotation ? marker.rotation : 0);
	sprite.tint =        marker.tint;
	sprite.interactive = true;
	sprite.lat =         marker.position.lat;
	sprite.lng =         marker.position.lng;
	sprite.x =           coords.x;
	sprite.y =           coords.y;
	sprite._title =      (marker.title ? marker.title[1] : null);
	sprite.mouseover =   leafletMarkerOnMouseOver;
	sprite.mouseout =    leafletMarkerOnMouseOut;

	// Rotate the sprite around its center
	sprite.anchor.set(0.5,0.5);
	// Set the scale to the current scale
	sprite.scale.set(me.scale);

	if (marker.popup) {
		// Popups closed by the user have to be synced with the server.
		const onPopupRemove = () => me.doEditEvent(taskId, editorId, [["LDClosePopup", marker.markerId]]);
		const popup =
			L.popup({closeOnClick: false})
				.setLatLng([sprite.lat, sprite.lng])
				.setContent(marker.popup[1])
				.on('remove', onPopupRemove);
			map.addLayer(popup);
		// If the corresponding sprite is removed, no event should be sent to the server.
		sprite.on('removed', () => {popup.off('remove', onPopupRemove); map.removeLayer(popup)});
	}

	me.container.addChild(sprite);

	const windows = me.windows.get(marker.markerId);
	if(!windows)
		return;

	windows.forEach(function(window) {window.onMarkerAdd(sprite)});
}

function leafletCreateMarkers(me, taskId, editorId, markers) {
	// Fetch here once to pass to the leafletCreateMarker function. Prevents constant fetching of the value
	const map = me.map;

	// Lose reference to the current array of children
	me.container.removeChildren();
	// Markers are arrays with two elements, the first is a string "Marker", which was needed in the Clean code, but not
	// so much here
	markers.forEach(m => leafletCreateMarker(me, map, taskId, editorId, m));
	// After creating all new values, force a redraw
	me.overlay.redraw();
}

function leafletPixiDraw(me, utils) {
	const container = utils.getContainer();
	const renderer = utils.getRenderer();
	const project = utils.latLngToLayerPoint;
	const scale = 1 / utils.getScale();
	const sprites = me.container.children;

	sprites.forEach(function(sprite) {
		const coords = project([sprite.lat, sprite.lng]);
		sprite.x = coords.x;
		sprite.y = coords.y;
		if (me.scale != scale) {
			sprite.scale.set(scale);
		}
	});

	me.scale = scale;
	renderer.render(container);
}
