import { Layer } from './Layer';
import { Fail, isFailure } from '../fail';
import { Permissions } from '../loader/Permission';
import { telemetry } from '../Telemetry';
import { SeverityLevel } from '@microsoft/applicationinsights-web';
/**
 * Manages a set of layers ({@link Layer}) of a specified format. Layers can be added and unloaded.
 */
export class LayerApi {
    _api;
    layerFormat;
    _serialize;
    _layers = new Map();
    /**
     *
     * @param _api API instance to use
     * @param layerFormat Type of layer. For example "sensor"
     * @param _serialize Methods to convert between layer objects (implements {@link MergableObject}) and their DTO's (data transferable object).
     * DTO's are what is actually stored in the layers (think of it as serialized layer objects).
     */
    constructor(_api, layerFormat, _serialize) {
        this._api = _api;
        this.layerFormat = layerFormat;
        this._serialize = _serialize;
    }
    /**
     * Get a layer for a specified change
     * @param change Change to get layer for.
     * @return Either the {@link Layer} or a {@link LayerFailure}. Use {@link isFailure} to check if the return value is a f{@link LayerFailure}
     * or a {@link Layer}.
     */
    async getOrLoadLayer(change) {
        // Abort early with instead of going to backend if we know we don't have permissions or
        // if layer definition does not exist. Backend would give us the same answer.
        const layerDefinition = change.availableLayerDefinitions.get(this.layerFormat);
        if (!layerDefinition.exists) {
            return this.notFoundLayerDefinitionFailure(change);
        }
        if (!layerDefinition.hasAny('view')) {
            return this.noPermissionsLayerDefinitionFailure(change);
        }
        let existingLayer = this._layers.get(change.id);
        if (!existingLayer) {
            existingLayer = new Layer(this._api, change, this.layerFormat, this._serialize);
            const ret = await existingLayer.loadAndMerge();
            if (!isFailure(ret)) {
                this._layers.set(change.id, existingLayer);
                return existingLayer;
            }
            return ret;
        }
        return existingLayer;
    }
    /**
     * Unloads layer of type {@link layerFormat} from specified change
     * @param change Change to unload layer for.
     * @return `true` if layer was unloaded. `false` if layer did not exist in {@link LayerApi}.
     */
    unload(change) {
        const id = typeof change === 'string' ? change : change.id;
        const existingLayer = this._layers.get(id);
        if (existingLayer) {
            // clear the layer so all objects get notified (deleted)
            existingLayer.clear();
        }
        return this._layers.delete(id);
    }
    noPermissionsLayerDefinitionFailure(change) {
        telemetry.trackTrace({
            message: `Permission: ${Permissions.toString('view')} is required to get or load layer.`,
            severityLevel: SeverityLevel.Information,
            properties: this.createFailureTraceProperties(change)
        });
        return Fail({
            httpStatus: 403,
            reason: `Permission: ${Permissions.toString('view')} is required to get or load layer.`
        });
    }
    notFoundLayerDefinitionFailure(change) {
        telemetry.trackTrace({
            message: `Valid layer definition not found.`,
            severityLevel: SeverityLevel.Information,
            properties: this.createFailureTraceProperties(change)
        });
        return Fail({
            httpStatus: 404,
            reason: `Valid layer definition '${this.layerFormat}' not found.
One of the following has occurred:
  * Layer definition is not valid for changes with format '${change.format}'.
  * User does not have any permissions at all for layer definition '${this.layerFormat}'.`
        });
    }
    createFailureTraceProperties(change) {
        return {
            layerDefinition: {
                id: this.layerFormat
            },
            change: {
                format: change.format,
                url: change.url
            }
        };
    }
}
//# sourceMappingURL=layerapi.js.map