"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 Tiles
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.LayerTileTreeReferenceHandler = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const internal_1 = require("../../tile/internal");
/** @internal */
class LayerTileTreeReferenceHandler {
    _layerTrees = new Array();
    isOverlay;
    _baseImageryLayerIncluded = false;
    _baseLayerSettings;
    _baseTransparent = false;
    _baseColor;
    _layerSettings;
    _ref;
    _mapTile;
    _detachFromDisplayStyle = [];
    get layerTrees() { return this._layerTrees; }
    get baseColor() { return this._baseColor; }
    get baseTransparent() { return this._baseTransparent; }
    get baseImageryLayerIncluded() { return this._baseImageryLayerIncluded; }
    get layerSettings() { return this._layerSettings; }
    discloseTileTrees(trees) {
        for (const imageryTree of this.layerTrees)
            if (imageryTree)
                trees.disclose(imageryTree);
    }
    constructor(ref, pIsOverlay, baseLayerSettings, layerSettings, mapTile = false) {
        this._ref = ref;
        this._baseLayerSettings = baseLayerSettings;
        this._layerSettings = layerSettings ? layerSettings : [];
        this.isOverlay = pIsOverlay;
        this._mapTile = mapTile;
        let tree;
        if (!this.isOverlay && this._baseLayerSettings !== undefined) {
            if (this._baseLayerSettings instanceof core_common_1.MapLayerSettings) {
                tree = (0, internal_1.createMapLayerTreeReference)(this._baseLayerSettings, 0, this._ref.iModel);
                this._baseTransparent = this._baseLayerSettings.transparency > 0;
            }
            else {
                this._baseColor = this._baseLayerSettings;
                this._baseTransparent = this._baseColor?.getTransparency() > 0;
            }
        }
        if (this._baseImageryLayerIncluded = (undefined !== tree))
            this._layerTrees.push(tree);
        if (undefined !== this._layerSettings) {
            for (let i = 0; i < this._layerSettings.length; i++)
                if (undefined !== (tree = (0, internal_1.createMapLayerTreeReference)(this._layerSettings[i], i + 1, this._ref.iModel)))
                    this._layerTrees.push(tree);
        }
    }
    detachFromDisplayStyle() {
        this._detachFromDisplayStyle.forEach((f) => f());
        this._detachFromDisplayStyle.length = 0;
    }
    initializeLayers(context) {
        // Map tiles handle refresh logic differently
        if (!this._mapTile) {
            const removals = this._detachFromDisplayStyle;
            if (0 === removals.length) {
                removals.push(context.viewport.displayStyle.settings.onMapImageryChanged.addListener((imagery) => {
                    this.setBaseLayerSettings(imagery.backgroundBase);
                    this.setLayerSettings(imagery.backgroundLayers);
                }));
                removals.push(context.viewport.onChangeView.addListener((vp, previousViewState) => {
                    if ((0, internal_1.compareMapLayer)(previousViewState, vp.view)) {
                        const currentImagery = vp.displayStyle.settings.mapImagery;
                        this.setBaseLayerSettings(currentImagery.backgroundBase);
                        this.setLayerSettings(currentImagery.backgroundLayers);
                    }
                }));
                removals.push(context.viewport.onViewedModelsChanged.addListener((viewport) => {
                    const currentImagery = viewport.displayStyle.settings.mapImagery;
                    if (currentImagery.backgroundLayers.length > 0) {
                        this.setBaseLayerSettings(currentImagery.backgroundBase);
                        this.setLayerSettings(currentImagery.backgroundLayers);
                        viewport.invalidateScene();
                    }
                }));
            }
        }
        let hasLoadedTileTree = false;
        const layerHandler = this._ref.treeOwner.load()?.layerHandler;
        if (undefined === layerHandler) {
            return hasLoadedTileTree; // Not loaded yet - or no layerHandler on tree.
        }
        layerHandler.layerImageryTrees.length = 0;
        if (0 === this._layerTrees.length) {
            return !this.isOverlay;
        }
        let treeIndex = this._layerTrees.length - 1;
        // Start displaying at the highest completely opaque layer...
        for (; treeIndex >= 1; treeIndex--) {
            const layerTreeRef = this._layerTrees[treeIndex];
            if (layerTreeRef?.isOpaque)
                break; // This layer is completely opaque and will obscure all others so ignore lower ones.
        }
        for (; treeIndex < this._layerTrees.length; treeIndex++) {
            const layerTreeRef = this._layerTrees[treeIndex];
            const hasValidTileTree = layerTreeRef && internal_1.TileTreeLoadStatus.NotFound !== layerTreeRef.treeOwner.loadStatus;
            const isImageryMapLayer = layerTreeRef instanceof internal_1.ImageryMapLayerTreeReference;
            const isLayerVisible = (isImageryMapLayer || (!isImageryMapLayer && layerTreeRef?.layerSettings.visible));
            if (!this._ref.shouldDrapeLayer(layerTreeRef)) {
                // If the layer is not to be displayed, then we should skip adding it to the tile tree.
                // The _shouldDrapeLayerFunc() function is sent in from MapTileTreeReference or RealityTileTree.
                hasLoadedTileTree = true; // ###TODO had to set this to true so addToScene actually works. alternative?
                continue;
            }
            // Load tile tree for each configured layer.
            // Note: Non-visible imagery layer are always added to allow proper tile tree scale range visibility reporting.
            if (hasValidTileTree
                && isLayerVisible
                && !layerTreeRef.layerSettings.allSubLayersInvisible) {
                const layerTree = layerTreeRef.treeOwner.load();
                if (layerTree !== undefined) {
                    hasLoadedTileTree = true;
                }
                else {
                    // Let's continue, there might be loaded tile tree in the list
                    continue;
                }
                // Add loaded TileTree
                const baseImageryLayer = this._baseImageryLayerIncluded && (treeIndex === 0);
                if (layerTree instanceof internal_1.ImageryMapTileTree) {
                    layerHandler.addImageryLayer(layerTree, layerTreeRef.layerSettings, treeIndex, baseImageryLayer);
                }
                else if (layerTreeRef instanceof internal_1.ModelMapLayerTileTreeReference)
                    layerHandler.addModelLayer(layerTreeRef, context);
            }
        }
        return hasLoadedTileTree;
    }
    setBaseLayerSettings(baseLayerSettings) {
        let tree;
        this._baseLayerSettings = baseLayerSettings;
        if (baseLayerSettings instanceof core_common_1.MapLayerSettings) {
            tree = (0, internal_1.createMapLayerTreeReference)(baseLayerSettings, 0, this._ref.iModel);
            this._baseColor = undefined;
            this._baseTransparent = baseLayerSettings.transparency > 0;
        }
        else {
            this._baseColor = baseLayerSettings;
            this._baseTransparent = this._baseColor.getTransparency() > 0;
        }
        if (tree) {
            if (this._baseImageryLayerIncluded)
                this._layerTrees[0] = tree;
            else
                this._layerTrees.splice(0, 0, tree);
        }
        else {
            if (this._baseImageryLayerIncluded)
                this._layerTrees.shift();
        }
        this._baseImageryLayerIncluded = tree !== undefined;
        this.clearLayers();
    }
    clearLayers() {
        const layerHandler = this._ref.treeOwner.tileTree?.layerHandler;
        if (undefined !== layerHandler) {
            layerHandler.clearLayers();
        }
    }
    setLayerSettings(layerSettings) {
        this._layerSettings = layerSettings;
        const baseLayerIndex = this._baseImageryLayerIncluded ? 1 : 0;
        this._layerTrees.length = Math.min(layerSettings.length + baseLayerIndex, this._layerTrees.length); // Truncate if number of layers reduced.
        for (let i = 0; i < layerSettings.length; i++) {
            const treeIndex = i + baseLayerIndex;
            if (treeIndex >= this._layerTrees.length || !this._layerTrees[treeIndex]?.layerSettings.displayMatches(layerSettings[i]))
                this._layerTrees[treeIndex] = (0, core_bentley_1.expectDefined)((0, internal_1.createMapLayerTreeReference)(layerSettings[i], treeIndex, this._ref.iModel));
        }
        this.clearLayers();
    }
}
exports.LayerTileTreeReferenceHandler = LayerTileTreeReferenceHandler;
//# sourceMappingURL=LayerTileTreeReferenceHandler.js.map