"use strict";
/*---------------------------------------------------------------------------------------------
* 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
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.MapLayerSources = exports.MapLayerSource = exports.MapLayerSourceStatus = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const core_geometry_1 = require("@itwin/core-geometry");
const IModelApp_1 = require("../../IModelApp");
const Request_1 = require("../../request/Request");
const internal_1 = require("../internal");
/** Values for return codes from [[MapLayerSource.validateSource]]
 * @public
 */
var MapLayerSourceStatus;
(function (MapLayerSourceStatus) {
    /** Layer source is valid */
    MapLayerSourceStatus[MapLayerSourceStatus["Valid"] = 0] = "Valid";
    /** Authorization has failed when accessing this layer source. */
    MapLayerSourceStatus[MapLayerSourceStatus["InvalidCredentials"] = 1] = "InvalidCredentials";
    /** Provided format id could not be resolved in [[MapLayerFormatRegistry]] */
    MapLayerSourceStatus[MapLayerSourceStatus["InvalidFormat"] = 2] = "InvalidFormat";
    /** The tiling schema of the source is not supported */
    MapLayerSourceStatus[MapLayerSourceStatus["InvalidTileTree"] = 3] = "InvalidTileTree";
    /** Could not not connect to remote server using the provided URL.*/
    MapLayerSourceStatus[MapLayerSourceStatus["InvalidUrl"] = 4] = "InvalidUrl";
    /** Authorization is required to access this map layer source. */
    MapLayerSourceStatus[MapLayerSourceStatus["RequireAuth"] = 5] = "RequireAuth";
    /** Map-layer coordinate system is not supported */
    MapLayerSourceStatus[MapLayerSourceStatus["InvalidCoordinateSystem"] = 6] = "InvalidCoordinateSystem";
    /** Format is not compatible with the URL provided.
     */
    MapLayerSourceStatus[MapLayerSourceStatus["IncompatibleFormat"] = 7] = "IncompatibleFormat";
})(MapLayerSourceStatus || (exports.MapLayerSourceStatus = MapLayerSourceStatus = {}));
/** A source for map layers. These may be catalogued for convenient use by users or applications.
 * @public
 */
class MapLayerSource {
    constructor(formatId = "WMS", name, url, baseMap = false, transparentBackground = true, savedQueryParams) {
        this.baseMap = false;
        this.formatId = formatId;
        this.name = name;
        this.url = url;
        this.baseMap = baseMap;
        this.transparentBackground = transparentBackground;
        this.savedQueryParams = savedQueryParams;
    }
    static fromJSON(json) {
        if (json === undefined)
            return undefined;
        return new MapLayerSource(json.formatId, json.name, json.url, json.baseMap, json.transparentBackground, json.queryParams);
    }
    async validateSource(ignoreCache) {
        return IModelApp_1.IModelApp.mapLayerFormatRegistry.validateSource({ source: this, ignoreCache });
    }
    /** @internal*/
    static fromBackgroundMapProps(props) {
        const provider = core_common_1.BackgroundMapProvider.fromBackgroundMapProps(props);
        const layerSettings = core_common_1.BaseMapLayerSettings.fromProvider(provider);
        if (undefined !== layerSettings) {
            const source = MapLayerSource.fromJSON(layerSettings);
            if (source) {
                source.baseMap = true;
                return source;
            }
        }
        return undefined;
    }
    toJSON() {
        return { url: this.url, name: this.name, formatId: this.formatId, transparentBackground: this.transparentBackground, queryParams: this.savedQueryParams };
    }
    toLayerSettings(subLayers) {
        // When MapLayerSetting is created from a MapLayerSource, sub-layers and credentials need to be set separately.
        const layerSettings = core_common_1.ImageMapLayerSettings.fromJSON({ ...this, subLayers });
        if (this.userName !== undefined || this.password !== undefined) {
            layerSettings?.setCredentials(this.userName, this.password);
        }
        if (this.savedQueryParams) {
            layerSettings.savedQueryParams = { ...this.savedQueryParams };
        }
        if (this.unsavedQueryParams) {
            layerSettings.unsavedQueryParams = { ...this.unsavedQueryParams };
        }
        return layerSettings;
    }
    getCredentials() {
        return this.userName && this.password ? { user: this.userName, password: this.password } : undefined;
    }
    /** Collect all query parameters
   * @beta
   */
    collectQueryParams() {
        let queryParams = {};
        if (this.savedQueryParams)
            queryParams = { ...this.savedQueryParams };
        if (this.unsavedQueryParams)
            queryParams = { ...queryParams, ...this.unsavedQueryParams };
        return queryParams;
    }
}
exports.MapLayerSource = MapLayerSource;
/** A collection of [[MapLayerSource]] objects.
 * @beta
 */
class MapLayerSources {
    constructor(_sources) {
        this._sources = _sources;
    }
    static getInstance() { return MapLayerSources._instance; }
    findByName(name, baseMap = false) {
        const nameTest = name.toLowerCase();
        for (const source of this._sources)
            if (source.baseMap === baseMap && source.name.toLowerCase().indexOf(nameTest) !== -1)
                return source;
        return undefined;
    }
    get layers() {
        const layers = new Array();
        this._sources.forEach((source) => {
            if (!source.baseMap)
                layers.push(source);
        });
        return layers;
    }
    get allSource() { return this._sources; }
    get bases() {
        const layers = new Array();
        this._sources.forEach((source) => {
            if (source.baseMap)
                layers.push(source);
        });
        return layers;
    }
    static getBingMapLayerSource() {
        const mapLayerSources = [];
        mapLayerSources.push(MapLayerSource.fromBackgroundMapProps({ providerName: "BingProvider", providerData: { mapType: core_common_1.BackgroundMapType.Street } }));
        mapLayerSources.push(MapLayerSource.fromBackgroundMapProps({ providerName: "BingProvider", providerData: { mapType: core_common_1.BackgroundMapType.Aerial } }));
        mapLayerSources.push(MapLayerSource.fromBackgroundMapProps({ providerName: "BingProvider", providerData: { mapType: core_common_1.BackgroundMapType.Hybrid } }));
        return mapLayerSources;
    }
    static getMapBoxLayerSource() {
        const mapLayerSources = [];
        mapLayerSources.push(MapLayerSource.fromBackgroundMapProps({ providerName: "MapBoxProvider", providerData: { mapType: core_common_1.BackgroundMapType.Street } }));
        mapLayerSources.push(MapLayerSource.fromBackgroundMapProps({ providerName: "MapBoxProvider", providerData: { mapType: core_common_1.BackgroundMapType.Aerial } }));
        mapLayerSources.push(MapLayerSource.fromBackgroundMapProps({ providerName: "MapBoxProvider", providerData: { mapType: core_common_1.BackgroundMapType.Hybrid } }));
        return mapLayerSources;
    }
    static async create(iModel, queryForPublicSources = false, addMapBoxSources = false) {
        if (!queryForPublicSources && MapLayerSources._instance)
            return MapLayerSources._instance;
        if (!iModel)
            iModel = IModelApp_1.IModelApp.viewManager.selectedView ? IModelApp_1.IModelApp.viewManager.selectedView.iModel : undefined;
        let sourceRange = internal_1.MapCartoRectangle.createMaximum();
        if (iModel) {
            const projectCenter = iModel.projectExtents.localXYZToWorld(.5, .5, .5);
            const cartoCenter = iModel.spatialToCartographicFromEcef(projectCenter);
            const globeRange = internal_1.MapCartoRectangle.createMaximum();
            const nearDelta = core_geometry_1.Point2d.create(globeRange.xLength() / 100, globeRange.yLength() / 100);
            sourceRange = internal_1.MapCartoRectangle.fromRadians(cartoCenter.longitude - nearDelta.x, cartoCenter.latitude - nearDelta.y, cartoCenter.longitude + nearDelta.x, cartoCenter.latitude + nearDelta.y);
        }
        const sources = new Array();
        const urlSet = new Set();
        const addSource = ((source) => {
            if (!urlSet.has(source.url)) {
                sources.push(source);
                urlSet.add(source.url);
            }
        });
        this.getBingMapLayerSource().forEach((source) => {
            addSource(source);
        });
        if (addMapBoxSources) {
            this.getMapBoxLayerSource().forEach((source) => {
                addSource(source);
            });
        }
        if (queryForPublicSources) {
            const sourcesJson = await (0, Request_1.request)(`${IModelApp_1.IModelApp.publicPath}assets/MapLayerSources.json`, "json");
            for (const sourceJson of sourcesJson) {
                const source = MapLayerSource.fromJSON(sourceJson);
                if (source)
                    addSource(source);
            }
            (await internal_1.ArcGisUtilities.getSourcesFromQuery(sourceRange)).forEach((queriedSource) => addSource(queriedSource));
        }
        sources.sort((a, b) => (0, core_bentley_1.compareStrings)(a.name.toLowerCase(), b.name.toLowerCase()));
        const mapLayerSources = new MapLayerSources(sources);
        MapLayerSources._instance = mapLayerSources;
        return mapLayerSources;
    }
    static async addSourceToMapLayerSources(mapLayerSource) {
        if (!MapLayerSources._instance || !mapLayerSource) {
            return undefined;
        }
        MapLayerSources._instance._sources = MapLayerSources._instance._sources.filter((source) => {
            return !(source.name === mapLayerSource.name || source.url === mapLayerSource.url);
        });
        MapLayerSources._instance._sources.push(mapLayerSource);
        MapLayerSources._instance._sources.sort((a, b) => (0, core_bentley_1.compareStrings)(a.name.toLowerCase(), b.name.toLowerCase()));
        return MapLayerSources._instance;
    }
    static removeLayerByName(name) {
        if (!MapLayerSources._instance) {
            return false;
        }
        // For now we only rely on the name
        const lengthBeforeRemove = MapLayerSources._instance._sources.length;
        MapLayerSources._instance._sources = MapLayerSources._instance._sources.filter((source) => {
            return (source.name !== name);
        });
        return (lengthBeforeRemove !== MapLayerSources._instance._sources.length);
    }
}
exports.MapLayerSources = MapLayerSources;
//# sourceMappingURL=MapLayerSources.js.map