Source: Models/LocationMarkerUtils.js

import CustomDataSource from 'terriajs-cesium/Source/DataSources/CustomDataSource';
import defined from 'terriajs-cesium/Source/Core/defined';
import Entity from 'terriajs-cesium/Source/DataSources/Entity.js';
import Ellipsoid from 'terriajs-cesium/Source/Core/Ellipsoid';
import Cartographic from 'terriajs-cesium/Source/Core/Cartographic';
import Cartesian3 from 'terriajs-cesium/Source/Core/Cartesian3';
import VerticalOrigin from 'terriajs-cesium/Source/Scene/VerticalOrigin';
import sampleTerrain from 'terriajs-cesium/Source/Core/sampleTerrain';
import prettifyCoordinates from '../Map/prettifyCoordinates';

import markerIcon from '../../wwwroot/images/map-pin.png';

const LOCATION_MARKER_DATA_SOURCE_NAME = 'TerriaJS Location Marker Points';

/**
 * Adds a location marker to the map with the position supplied in the result, adding a data source to terria if one hasn't
 * already been added, and removing all previously added markers in that data source. This data source is stored in
 * terria.locationMarker.
 */
export function addMarker(terria, result) {
    if (!terria.locationMarker) {
        terria.locationMarker = new CustomDataSource(LOCATION_MARKER_DATA_SOURCE_NAME);
    }

    if (!terria.dataSources.contains(terria.locationMarker)) {
        terria.dataSources.add(terria.locationMarker);
    }

    terria.locationMarker.entities.removeAll();

    const cartographicPosition = Cartographic.fromDegrees(result.location.longitude, result.location.latitude);

    const displayCoords = prettifyCoordinates(result.location.longitude, result.location.latitude, {digits: 5});

    const firstPointEntity = new Entity({
        name: result.name,
        position: Ellipsoid.WGS84.cartographicToCartesian(cartographicPosition),
        description: `<table><tr><td>Lat / Lon</td><td>${displayCoords.latitude}, ${displayCoords.longitude}</td></tr></table>`,
        billboard: {
            image: markerIcon,
            scale: 0.5,
            eyeOffset: new Cartesian3(0.0, 0.0, 50.0),
            verticalOrigin: VerticalOrigin.BOTTOM
        }
    });

    if (terria.cesium && terria.cesium.scene && terria.cesium.scene.globe && terria.cesium.scene.globe.terrainProvider) {
        correctEntityHeight(firstPointEntity, cartographicPosition, terria.cesium.scene.globe.terrainProvider, 15);
    }

    terria.locationMarker.entities.add(firstPointEntity);
}

/**
 * Gets the most detailed height from terrainProvider at currentCartographicPosition and updates entity position.
 * It starts querying at levelHint and makes its way down to level zero.
 */
function correctEntityHeight(entity, currentCartographicPosition, terrainProvider, levelHint) {
    sampleTerrain(terrainProvider, levelHint, [currentCartographicPosition]).then(function (updatedPositions) {
        if (updatedPositions[0].height !== undefined) {
            entity.position = Ellipsoid.WGS84.cartographicToCartesian(updatedPositions[0]);
        } else if (levelHint > 0) {
            correctEntityHeight(entity, currentCartographicPosition, terrainProvider, levelHint - 1);
        }
    });
}

/** Removes a marker previously added in {@link #addMarker}. */
export function removeMarker(terria) {
    terria.dataSources.remove(terria.locationMarker);
    terria.locationMarker = undefined;
}

/** Determines whether the location marker is visible previously added in {@link #addMarker}. */
export function markerVisible(terria) {
    return defined(terria.locationMarker);
}

/**
 * The name given to the data source created by {@link #addMarker}.
 */
export { LOCATION_MARKER_DATA_SOURCE_NAME };