/*---------------------------------------------------------------------------------------------
* 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
 */
import { BeTimePoint, dispose } from "@itwin/core-bentley";
import { calculateEcefToDbTransformAtLocation } from "../BackgroundMapGeometry";
import { IModelApp } from "../IModelApp";
/** Describes the current state of a [[TileTree]]. TileTrees are loaded asynchronously and may be unloaded after a period of disuse.
 * @see [[TileTreeOwner]].
 * @public
 * @extensions
 */
export var TileTreeLoadStatus;
(function (TileTreeLoadStatus) {
    /** No attempt to load the tile tree has yet been made. */
    TileTreeLoadStatus[TileTreeLoadStatus["NotLoaded"] = 0] = "NotLoaded";
    /** The tile tree is in the process of being loaded. */
    TileTreeLoadStatus[TileTreeLoadStatus["Loading"] = 1] = "Loading";
    /** The tile tree has been successfully loaded. */
    TileTreeLoadStatus[TileTreeLoadStatus["Loaded"] = 2] = "Loaded";
    /** An attempt to load the tile tree failed. */
    TileTreeLoadStatus[TileTreeLoadStatus["NotFound"] = 3] = "NotFound";
})(TileTreeLoadStatus || (TileTreeLoadStatus = {}));
/** A hierarchical level-of-detail tree of [3d Tiles](https://github.com/CesiumGS/3d-tiles) to be rendered in a [[Viewport]].
 * Tile trees originate from a variety of sources:
 *  - Each [[GeometricModelState]] can supply its graphics as a tile tree;
 *  - A [[DisplayStyleState]]'s map settings or reality models;
 *  - [ViewAttachment]($backend)s in a [[SheetModelState]];
 *  - [[TiledGraphicsProvider]]s associated with a viewport.
 *
 * The same TileTree can be displayed in any number of viewports using multiple [[TileTreeReference]]s.
 * A TileTree's lifetime is managed by a [[TileTreeOwner]].
 *
 * @note Some methods carry a warning that they should **not** be overridden by subclasses; typically a protected method exists that can be
 * overridden instead to customize the behavior. For example, [[selectTiles]] should not be overridden; instead, override the[[_selectTiles]] method
 * that it calls.
 * @public
 * @extensions
 */
export class TileTree {
    /** @internal */
    get loadPriority() { return this._loadPriority; }
    /** True if this tile tree has no bounds - e.g., a tile tree representing a globe is unbounded. */
    get isContentUnbounded() {
        return false;
    }
    /** True if this tile tree contains 2d graphics. */
    get is2d() { return !this.is3d; }
    /** @internal */
    get isPointCloud() { return false; }
    /** @internal */
    get clipVolume() { return this._clipVolume; }
    /** The volume of space occupied by this tile tree. */
    get range() { return this.rootTile.range; }
    /** The most recent time at which tiles [[selectTiles]] was called. */
    get lastSelectedTime() { return this._lastSelected; }
    /** True if a tile and its child tiles should not be drawn simultaneously.
     * Default: true.
     */
    get parentsAndChildrenExclusive() { return true; }
    /** Constructor */
    constructor(params) {
        this._isDisposed = false;
        /** @internal */
        this._lastSelected = BeTimePoint.now();
        this._lastSelected = BeTimePoint.now();
        this.iModel = params.iModel;
        this.iModelTransform = params.location;
        this._clipVolume = params.clipVolume;
        this.modelId = params.modelId;
        this.id = params.id;
        this.contentRange = params.contentRange;
        const admin = IModelApp.tileAdmin;
        this._loadPriority = params.priority;
        this.expirationTime = params.expirationTime ?? admin.tileExpirationTime;
    }
    /** Selects tiles of appropriate resolution for some purpose like drawing to the screen, producing a shadow map, etc.
     * @note Do **not** override this method. Implement [[_selectTiles]].
     */
    selectTiles(args) {
        this._lastSelected = BeTimePoint.now();
        const tiles = this._selectTiles(args);
        IModelApp.tileAdmin.addTilesForUser(args.context.viewport, tiles, args.readyTiles, args.touchedTiles);
        args.processSelectedTiles(tiles);
        return tiles;
    }
    /** True if [[dispose]] has been called on this tile tree. */
    get isDisposed() { return this._isDisposed; }
    /** Dispose of this tree and any resources owned by it. This is typically invoked by a [[TileTreeOwner]]. */
    dispose() {
        if (this.isDisposed)
            return;
        this._isDisposed = true;
        dispose(this.rootTile);
    }
    /** @internal */
    collectStatistics(stats) {
        this.rootTile.collectStatistics(stats);
    }
    /** Returns the number of [[Tile]]s currently in memory belonging to this tree, primarily for debugging. */
    countTiles() {
        return 1 + this.rootTile.countDescendants();
    }
    /** @internal */
    accumulateTransformedRange(range, matrix, location, frustumPlanes) {
        this.rootTile.extendRangeForContent(range, matrix, location, frustumPlanes);
    }
    /**
     * Return the transform from the tile tree's coordinate space to [ECEF](https://en.wikipedia.org/wiki/ECEF) (Earth Centered Earth Fixed) coordinates.
     * If a geographic coordinate system is present then this transform will be calculated at the tile tree center.
     * @beta
     */
    async getEcefTransform() {
        if (!this.iModel.ecefLocation)
            return undefined;
        let dbToEcef;
        const range = this.contentRange ? this.contentRange : this.range;
        const center = range.localXYZToWorld(.5, .5, .5);
        if (center) {
            this.iModelTransform.multiplyPoint3d(center, center);
            const ecefToDb = await calculateEcefToDbTransformAtLocation(center, this.iModel);
            dbToEcef = ecefToDb?.inverse();
        }
        if (!dbToEcef)
            dbToEcef = this.iModel.ecefLocation.getTransform();
        return dbToEcef.multiplyTransformTransform(this.iModelTransform);
    }
    /** Populate [[TileGeometryCollector.polyfaces]] with geometry obtained from this tile tree's tiles satisfying the collector's criteria.
     * The base implementation does nothing.
     * @see [[TileTreeReference.createGeometryTreeReference]] to attempt to create a TileTree that can collect geometry.
     * @beta
     */
    collectTileGeometry(_collector) {
    }
}
//# sourceMappingURL=TileTree.js.map