/*---------------------------------------------------------------------------------------------
* 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 { compareNumbers, comparePossiblyUndefined, compareStrings, compareStringsOrUndefined, Id64 } from "@itwin/core-bentley";
import { BatchType, iModelTileTreeIdToString, RenderMode, } from "@itwin/core-common";
import { IModelApp } from "../IModelApp";
import { GeometricModelState } from "../ModelState";
import { IModelTileTree, iModelTileTreeParamsFromJSON, TileTreeLoadStatus, TileTreeReference, } from "./internal";
function compareIds(lhs, rhs) {
    return compareNumbers(lhs.type, rhs.type) || compareNumbers(lhs.expansion, rhs.expansion)
        || compareStrings(lhs.modelId, rhs.modelId) || compareStringsOrUndefined(lhs.animationId, rhs.animationId)
        || comparePossiblyUndefined((x, y) => x.compareTo(y), lhs.timeline, rhs.timeline);
}
class ClassifierTreeSupplier {
    constructor() {
        this._nonexistentTreeOwner = {
            tileTree: undefined,
            loadStatus: TileTreeLoadStatus.NotFound,
            load: () => undefined,
            dispose: () => undefined,
            loadTree: async () => undefined,
            iModel: undefined,
        };
    }
    compareTileTreeIds(lhs, rhs) {
        return compareIds(lhs, rhs);
    }
    async createTileTree(id, iModel) {
        await iModel.models.load(id.modelId);
        const model = iModel.models.getLoaded(id.modelId);
        if (undefined === model || !(model instanceof GeometricModelState))
            return undefined;
        const idStr = iModelTileTreeIdToString(id.modelId, id, IModelApp.tileAdmin);
        const props = await IModelApp.tileAdmin.requestTileTreeProps(iModel, idStr);
        const params = iModelTileTreeParamsFromJSON(props, iModel, id.modelId, {
            edges: false,
            allowInstancing: false,
            is3d: true,
            batchType: id.type,
            timeline: id.timeline,
        });
        return new IModelTileTree(params, id);
    }
    getOwner(id, iModel) {
        return Id64.isValid(id.modelId) ? iModel.tiles.getTileTreeOwner(id, this) : this._nonexistentTreeOwner;
    }
    addModelsAnimatedByScript(modelIds, scriptSourceId, trees) {
        // Note: This is invoked when an element hosting a schedule script is updated - it doesn't care about frontend schedule scripts.
        for (const tree of trees)
            if (scriptSourceId === tree.id.animationId)
                modelIds.add(tree.id.modelId);
    }
    addSpatialModels(modelIds, trees) {
        for (const tree of trees)
            modelIds.add(tree.id.modelId);
    }
}
const classifierTreeSupplier = new ClassifierTreeSupplier();
/** @internal */
export class SpatialClassifierTileTreeReference extends TileTreeReference {
    get transparency() { return undefined; }
}
/** @internal */
class ClassifierTreeReference extends SpatialClassifierTileTreeReference {
    constructor(classifiers, classifiedTree, iModel, source) {
        super();
        this._id = createClassifierId(classifiers.active, source);
        this._source = source;
        this._iModel = iModel;
        this._classifiers = classifiers;
        this._classifiedTree = classifiedTree;
        this._owner = classifierTreeSupplier.getOwner(this._id, iModel);
    }
    get classifiers() { return this._classifiers; }
    get activeClassifier() { return this.classifiers.activeClassifier; }
    get castsShadows() {
        return false;
    }
    get treeOwner() {
        const newId = createClassifierId(this._classifiers.active, this._source);
        if (0 !== compareIds(this._id, newId)) {
            this._id = newId;
            this._owner = classifierTreeSupplier.getOwner(this._id, this._iModel);
        }
        return this.activeClassifier?.tileTreeReference?.treeOwner ?? this._owner;
    }
    discloseTileTrees(trees) {
        // NB: We do NOT call super because we don't use our tree if no classifier is active.
        trees.disclose(this._classifiedTree);
        const classifier = this.activeClassifier;
        const classifierTree = undefined !== classifier ? this.treeOwner.tileTree : undefined;
        if (undefined !== classifierTree)
            trees.add(classifierTree);
    }
    get isPlanar() {
        if (this.activeClassifier?.flags.isVolumeClassifier) {
            return false;
        }
        return true;
    }
    get viewFlags() {
        return {
            renderMode: RenderMode.SmoothShade,
            transparency: true, // Igored for point clouds as they don't support transparency.
            textures: false,
            lighting: false,
            shadows: false,
            monochrome: false,
            materials: false,
            ambientOcclusion: false,
            visibleEdges: false,
            hiddenEdges: false,
        };
    }
    // Add volume classifiers to scene (planar classifiers are added seperately.)
    addToScene(context) {
        if (this.isPlanar)
            return;
        const classifiedTree = this._classifiedTree.treeOwner.load();
        if (undefined === classifiedTree)
            return;
        const classifier = this._classifiers.activeClassifier;
        if (undefined === classifier)
            return;
        const classifierTree = this.treeOwner.load();
        if (undefined === classifierTree)
            return;
        context.setVolumeClassifier(classifier, classifiedTree.modelId);
        super.addToScene(context);
    }
}
/** @internal */
export function createClassifierTileTreeReference(classifiers, classifiedTree, iModel, source) {
    return new ClassifierTreeReference(classifiers, classifiedTree, iModel, source);
}
function createClassifierId(classifier, source) {
    if (undefined === classifier)
        return { modelId: Id64.invalid, type: BatchType.PlanarClassifier, expansion: 0, animationId: undefined };
    const type = classifier.flags.isVolumeClassifier ? BatchType.VolumeClassifier : BatchType.PlanarClassifier;
    const scriptInfo = IModelApp.tileAdmin.getScriptInfoForTreeId(classifier.modelId, source?.scheduleScriptReference); // eslint-disable-line @typescript-eslint/no-deprecated
    return {
        modelId: classifier.modelId,
        type,
        expansion: classifier.expand,
        animationId: scriptInfo?.animationId,
        timeline: scriptInfo?.timeline,
    };
}
//# sourceMappingURL=ClassifierTileTree.js.map