import { telemetry } from '../Telemetry';
import { Uint32Bits } from '../Uint32Bits';
import { IfcMaterialRenderProperty } from './CustomBabylonMaterials/IfcMaterial';
/**
 * Base class for recording render property statistics for a collection of IFC product meshes.
 * @internal NOTE: Internal APIs. Subject to change. Use of these APIs in production applications is not supported.
 */
export class BaseProductMeshesGroupRenderInfo {
    parent;
    _state = {
        ignoreClipPlanesCount: 0,
        outlinedCount: 0,
        visibleCount: 0,
        ghostOutlineCount: 0,
        count: 0
    };
    /**
     * Constructor.
     * @param parent - The parent render info object. If not set, this is the root object.
     */
    constructor(parent) {
        this.parent = parent;
    }
    /**
     * Check if the current state is valid.
     */
    get isValid() {
        return (this._state.outlinedCount >= 0 &&
            this._state.visibleCount >= 0 &&
            this._state.ghostOutlineCount >= 0 &&
            this._state.ignoreClipPlanesCount >= 0 &&
            this._state.outlinedCount <= this._state.count &&
            this._state.visibleCount <= this._state.count &&
            this._state.ghostOutlineCount <= this._state.count &&
            this._state.ignoreClipPlanesCount <= this._state.count);
    }
    /**
     * Get the current state of render properties.
     */
    get state() {
        return this._state;
    }
    _lastLoggedState = {
        ignoreClipPlanesCount: 0,
        outlinedCount: 0,
        visibleCount: 0,
        ghostOutlineCount: 0,
        count: 0
    };
    /**
     * Update the render properties based on the current and previous render properties.
     * @param currentRenderProperty - The current render property.
     * @param prevRenderProperty - The previous render property.
     */
    updateFromRenderProperty(currentRenderProperty, prevRenderProperty) {
        const prevVisibility = Uint32Bits.getNumber(prevRenderProperty, IfcMaterialRenderProperty.visibility, 1);
        const currentVisibility = Uint32Bits.getNumber(currentRenderProperty, IfcMaterialRenderProperty.visibility, 1);
        const prevOutline = Uint32Bits.getNumber(prevRenderProperty, IfcMaterialRenderProperty.outline, 1);
        const currentOutline = Uint32Bits.getNumber(currentRenderProperty, IfcMaterialRenderProperty.outline, 1);
        const prevClipPlaneIgnores = Uint32Bits.getNumber(prevRenderProperty, IfcMaterialRenderProperty.ignoreClipPlanes, 1);
        const currentClipPlaneIgnores = Uint32Bits.getNumber(currentRenderProperty, IfcMaterialRenderProperty.ignoreClipPlanes, 1);
        // Using type coercion to convert boolean to number for performance optimization
        const prevGhostOutline = 0 +
            (Uint32Bits.has(prevRenderProperty, IfcMaterialRenderProperty.depthWriteIgnoresVisibility) &&
                !prevVisibility);
        const currentGhostOutline = 0 +
            (Uint32Bits.has(currentRenderProperty, IfcMaterialRenderProperty.depthWriteIgnoresVisibility) &&
                !currentVisibility);
        this._state.visibleCount = this._state.visibleCount + currentVisibility - prevVisibility;
        this._state.outlinedCount = this._state.outlinedCount + currentOutline - prevOutline;
        this._state.ghostOutlineCount = this._state.ghostOutlineCount + currentGhostOutline - prevGhostOutline;
        this._state.ignoreClipPlanesCount =
            this._state.ignoreClipPlanesCount + currentClipPlaneIgnores - prevClipPlaneIgnores;
        // Check that counts are valid. This should never result in anything else but true. However
        // it is critical code so we want to be sure that we dont introduce any bugs in the future
        if (!this.isValid) {
            this.logIfCountsDiffer();
        }
    }
    /**
     * Log the current state if it differs from the last logged state.
     */
    logIfCountsDiffer() {
        // Why have such as complex check for differences before logging? Because otherwise serious telemetry spamming may occur
        // as this is executed whenever a render property is changed (and there is a error). As there can be millions
        // of render properties (potentially chaning every frame) this would result in a LOT of telemetry spamming.
        // Now just to be clear. The error should never really occur so this is just a safety measure.
        let statesDiffer = false;
        for (const prop of Object.keys(this._state)) {
            statesDiffer ||=
                this._state[prop] !==
                    this._lastLoggedState[prop];
            this._lastLoggedState[prop] =
                this._state[prop];
        }
        if (statesDiffer) {
            telemetry.trackTrace({ message: 'Incorrect render property counts', severityLevel: 3 }, {
                clipPlanesIgnoreCount: this._state.ignoreClipPlanesCount,
                count: this._state.count,
                outlinedCount: this._state.outlinedCount,
                visibleCount: this._state.visibleCount,
                ghostOutlineCount: this._state.ghostOutlineCount
            });
        }
    }
    /**
     * Set the state of the render properties in {@link state} to 0.
     */
    clearState() {
        for (const prop of Object.keys(this._state)) {
            this._state[prop] = 0;
            this._lastLoggedState[prop] = 0;
        }
    }
}
//# sourceMappingURL=BaseProductMeshesGroupRenderInfo.js.map