import {Vector2} from 'three';

/**
 * Location utils contains utils to access the user location (GPS, IP location or wifi) and convert data between representations.
 *
 * Devices with a GPS, for example, can take a minute or more to get a GPS fix, so less accurate data (IP location or wifi) may be returned.
 */
export class UnitsUtils 
{
	/**
	 * Aproximated radius of earth in meters.
	 */
	public static EARTH_RADIUS: number = 6378137;

	/**
	 * Earth equator perimeter in meters.
	 */
	public static EARTH_PERIMETER: number = 2 * Math.PI * UnitsUtils.EARTH_RADIUS;

	/**
	 * Earth equator perimeter in meters.
	 */
	public static EARTH_ORIGIN: number = UnitsUtils.EARTH_PERIMETER / 2.0;

	/**
	 * Get the current geolocation from the browser using the location API.
	 *
	 * This location can be provided from GPS measure, estimated IP location or any other system available in the host. Precision may vary.
	 *
	 * @param onResult - Callback function onResult(coords, timestamp).
	 * @param onError - Callback to handle errors.
	 */
	public static get(onResult: Function, onError: Function): void
	{
		navigator.geolocation.getCurrentPosition(function(result) 
		{
			onResult(result.coords, result.timestamp);
		// @ts-ignore
		}, onError);
	}

	/**
	 * Converts given lat/lon in WGS84 Datum to XY in Spherical Mercator EPSG:900913.
	 *
	 * @param latitude - Latitude value in degrees.
	 * @param longitude - Longitude value in degrees.
	 */
	public static datumsToSpherical(latitude: number, longitude: number): Vector2
	{
		const x = longitude * UnitsUtils.EARTH_ORIGIN / 180.0;
		let y = Math.log(Math.tan((90 + latitude) * Math.PI / 360.0)) / (Math.PI / 180.0);

		y = y * UnitsUtils.EARTH_ORIGIN / 180.0;

		return new Vector2(x, y);
	}

	/**
	 * Converts XY point from Spherical Mercator EPSG:900913 to lat/lon in WGS84 Datum.
	 *
	 * @param x - X coordinate.
	 * @param y - Y coordinate.
	 */
	public static sphericalToDatums(x: number, y: number): {latitude: number, longitude: number}
	{
		const longitude = x / UnitsUtils.EARTH_ORIGIN * 180.0;
		let latitude = y / UnitsUtils.EARTH_ORIGIN * 180.0;

		latitude = 180.0 / Math.PI * (2 * Math.atan(Math.exp(latitude * Math.PI / 180.0)) - Math.PI / 2.0);

		return {latitude: latitude, longitude: longitude};
	}

	/**
	 * Converts quad tree zoom/x/y to lat/lon in WGS84 Datum.
	 *
	 * @param zoom - Zoom level of the quad tree.
	 * @param x - X coordinate.
	 * @param y - Y coordinate.
	 */
	public static quadtreeToDatums(zoom: number, x: number, y: number): {latitude: number, longitude: number}
	{
		const n = Math.pow(2.0, zoom);
		const longitude = x / n * 360.0 - 180.0;
		const latitudeRad = Math.atan(Math.sinh(Math.PI * (1.0 - 2.0 * y / n)));
		const latitude = 180.0 * (latitudeRad / Math.PI);

		return {latitude: latitude, longitude: longitude};
	}
}