Source: utils.js

/* A few functions that may be useful in other modules. */

/**
 * Given a geoJSON geometry object's coordinates, return the object, but with
 * all the coordinates reversed. <br /point.geometry && point.geometry.coordinates && >
 * 
 * Why? GeoJSON coordinates are in lngLat format by default, while Leaflet uses latLng.
 * L.geoJSON will auto-reverse the order of a GeoJSON object's coordinates, as it
 * expects geoJSON coordinates to be lngLat. However, normal, non-GeoJSON-specific Leaflet
 * methods expect Leaflet's latLng pairs and won't auto-reverse, so we have to do that
 * manually if we're preprocessing the GeoJSON data before passing it to L.geoJSON.
 * 
 * @param {Array<number|Array<number|Array<number>>>} coordinates - GeoJSON coordinates for a point, (multi-)line, or (multi-)polygon.
 * @returns {Array<number|Array<number|Array<number>>>} - Reversed geoJSON coordinates for a point, (multi-)line, or (multi-)polygon.
 */
function reversedCoordinates(coordinates) {
	let reversed = coordinates.slice();
	if (typeof coordinates[0] != "number") {
		for (let inner_coordinates of coordinates) {
			reversed.splice(reversed.indexOf(inner_coordinates), 1, reversedCoordinates(inner_coordinates));
		}
	}
	else {
		reversed = [coordinates[1], coordinates[0]];
	}

	return reversed;
}

/**
 * Given an array, check whether it can represent the coordinates of a point.
 *
 * @param {Array} array - Array to check.
 * @returns {boolean} - Whether the array can be the coordinates of a point.
 */
function isPointCoordinates(array) {
	if (array.length !== 2 || 
		typeof(array[0]) !== "number" ||
		typeof(array[1]) !== "number") {
		return false;
	}

	return true;
}

/**
 * Given either a GeoJSON feature, L.latLng, or coordinate array containing the coordinates of a point,
 * return an array of the coordinates.
 *
 * @param {Point|Array<number>|LatLng} point - The data containing the point's coordinates (latitude & longitude).
 * @returns {Array<number>} - Array of the point's coordinates. I.e.: [lng, lat].
 */
function pointToCoordinateArray(point) {
	let coordinate_array;

	if (typeof(point.lat) === "number" && typeof(point.lng) === "number") {
		coordinate_array = [point.lng, point.lat];
	}
	else if (point.geometry && point.geometry.coordinates && isPointCoordinates(point.geometry.coordinates)) {
		coordinate_array = point.geometry.coordinates;
	}
	else if (isPointCoordinates(point)) {
		coordinate_array = point;
	}
	else {
		throw new Error("Invalid point: point must either be array of 2 coordinates, or an L.latLng.");
	}

	return coordinate_array;
}

/**
 * Given two coordinate arrays, get their intersections.
 * 
 * @param {array<array<number>>} arr_a - Array of coordinate pairs.
 * @param {array<array<number>>} arr_b - Array of coordinate pairs.
 * @param {array<number>} ids - 2-element array whose elements are IDs for arr_a and arr_b respectively.
 *
 * @returns {Array<Array<number|Object<number, number>>>} - Array whose elements are the intersections' cooridinate-pairs if
 * ids is empty, or otherwise whose elements are arrays each of whose first element is an
 * intersection's coordinate-pair and whose second element is an object mapping each array's ID (supplied by ids) 
 * to the index of the intersection's coordinate-pair in that array.
 */
function getIntersections(arr_a, arr_b, ids = []) {
	let intersections = [];

	for (let i = 0; i < arr_a.length; i++) {
		let el_a = arr_a[i];

		for (let j = 0; j < arr_b.length; j++) {
			let el_b = arr_b[j];
			
			if (isPointCoordinates(el_a) && isPointCoordinates(el_b)) {
				if (el_a[0] === el_b[0] && el_a[1] === el_b[1]) {
					let new_intersection;

					if (ids.length === 2) {
						let identified_intersections = {};
						identified_intersections[ids[0]] = i,
						identified_intersections[ids[1]] = j,
						new_intersection = [el_a, identified_intersections];
					}
					else {
						new_intersection = el_a;
					}
				
					intersections.push(new_intersection);
				}
			}
			else {
				throw new Error("Every element of each array must be a coordinate pair array.");
			}
		}
	}

	return intersections;
}

exports.getIntersections = getIntersections;
exports.reversedCoordinates = reversedCoordinates;
exports.isPointCoordinates = isPointCoordinates;
exports.pointToCoordinateArray = pointToCoordinateArray;