/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module MapLayers
 */
import { assert, Logger } from "@itwin/core-bentley";
import { IModelApp } from "../../IModelApp";
import { internalMapLayerImageryFormats, MapLayerSource, MapLayerSourceStatus } from "../internal";
const loggerCategory = "ArcGISFeatureProvider";
/**
 * Class representing a map-layer format.
 * Each format has it's unique 'formatId' string, used to uniquely identify a format in the [[MapLayerFormatRegistry]].
 * When creating an [[ImageMapLayerSettings]] object, a format needs to be specified this 'formatId'.
 * The MapLayerFormat object can later be used to validate a source, or create a provider.
 *
 * Subclasses should override formatId, [[MapLayerFormat.createImageryProvider]], and [[MapLayerFormat.createMapLayerTree]].
 * @public
 */
export class MapLayerFormat {
    /** Register the current format in the [[MapLayerFormatRegistry]]. */
    static register() { IModelApp.mapLayerFormatRegistry.register(this); }
    /**
     * Allow a source of a specific format to be validated before being attached as a map-layer.
     * @param _url The URL of the source.
     * @param _userName The username to access the source if needed.
     * @param _password The password to access the source if needed.
     * @param _ignoreCache Flag to skip cache lookup (i.e. force a new server request).
     * @returns Validation Status. If successful, a list of available sub-layers may also be returned.
     */
    static async validateSource(_url, _userName, _password, _ignoreCache, _accesKey) { return { status: MapLayerSourceStatus.Valid }; }
    /** Allow a source object to be validated before being attached as a map-layer.
      * @beta
    */
    static async validate(args) {
        return this.validateSource(args.source.url, args.source.userName, args.source.password, args.ignoreCache);
    }
    /**
     * Create a [[MapLayerImageryProvider]] that will be used to feed data in a map-layer tile tree.
     * @param _settings The map layer settings to be applied to the imagery provider.
     * @returns Returns the new imagery provider.
     * @beta
     */
    static createImageryProvider(_settings) { assert(false); }
    /**
     * Creates a MapLayerTileTreeReference for this map layer format.
     * @param _layerSettings Map layer settings that are applied to the MapLayerTileTreeReference.
     * @param _layerIndex The index of the associated map layer.
     * @param _iModel The iModel containing the MapLayerTileTreeReference.
     * @returns Returns the new tile tree reference.
     * @beta
     */
    static createMapLayerTree(_layerSettings, _layerIndex, _iModel) {
        assert(false);
        return undefined;
    }
}
/**
 * A registry of MapLayerFormats identified by their unique format IDs. The registry can be accessed via [[IModelApp.mapLayerFormatRegistry]].
 * @public
 */
export class MapLayerFormatRegistry {
    constructor(opts) {
        this._formats = new Map();
        this._configOptions = opts ?? {};
        internalMapLayerImageryFormats.forEach((format) => this.register(format));
    }
    isRegistered(formatId) { return this._formats.get(formatId) !== undefined; }
    register(formatClass) {
        if (formatClass.formatId.length === 0)
            return; // must be an abstract class, ignore it
        this._formats.set(formatClass.formatId, { type: formatClass });
    }
    /** @beta */
    setAccessClient(formatId, accessClient) {
        const entry = this._formats.get(formatId);
        if (entry !== undefined) {
            entry.accessClient = accessClient;
            return true;
        }
        return false;
    }
    /** @beta */
    getAccessClient(formatId) {
        if (formatId.length === 0)
            return undefined;
        return this._formats.get(formatId)?.accessClient;
    }
    get configOptions() {
        return this._configOptions;
    }
    /** @internal */
    createImageryMapLayerTree(layerSettings, layerIndex, iModel) {
        const entry = this._formats.get(layerSettings.formatId);
        const format = entry?.type;
        if (format === undefined) {
            Logger.logError(loggerCategory, `Could not find format '${layerSettings.formatId}' in registry`);
            return undefined;
        }
        return format.createMapLayerTree(layerSettings, layerIndex, iModel);
    }
    /**
     * Returns a [[MapLayerImageryProvider]] based on the provided [[ImageMapLayerSettings]] object.
     * @internal
     */
    createImageryProvider(layerSettings) {
        const entry = this._formats.get(layerSettings.formatId);
        const format = entry?.type;
        if (this._configOptions[layerSettings.formatId] !== undefined) {
            const keyValuePair = this._configOptions[layerSettings.formatId];
            const key = { key: keyValuePair.key, value: keyValuePair.value };
            layerSettings = layerSettings.clone({ accessKey: key });
        }
        return (format === undefined) ? undefined : format.createImageryProvider(layerSettings);
    }
    /** @internal*/
    async validateSource(formatIdOrArgs, url, userName, password, ignoreCache) {
        let format;
        let args;
        if (typeof formatIdOrArgs == "string" && url !== undefined) {
            const formatId = formatIdOrArgs;
            const entry = this._formats.get(formatId);
            format = entry?.type;
            if (format !== undefined) {
                const source = MapLayerSource.fromJSON({ name: "", formatId, url });
                if (source !== undefined) {
                    args = { source, ignoreCache };
                    source.userName = userName;
                    source.password = password;
                }
            }
        }
        else if (typeof formatIdOrArgs !== "string") {
            const entry = this._formats.get(formatIdOrArgs.source.formatId);
            format = entry?.type;
            args = formatIdOrArgs;
        }
        if (!args || !format)
            return { status: MapLayerSourceStatus.InvalidFormat };
        return format.validate(args);
    }
}
//# sourceMappingURL=MapLayerFormatRegistry.js.map