"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 ViewDefinitions
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.DisplayStyle3d = exports.DisplayStyle2d = exports.DisplayStyle = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const Element_1 = require("./Element");
const EditTxn_1 = require("./EditTxn");
const Symbols_1 = require("./internal/Symbols");
/** A DisplayStyle defines the parameters for 'styling' the contents of a view.
 * Internally a DisplayStyle consists of a dictionary of several named 'styles' describing specific aspects of the display style as a whole.
 * Many ViewDefinitions may share the same DisplayStyle.
 * @public @preview
 */
class DisplayStyle extends Element_1.DefinitionElement {
    static get className() { return "DisplayStyle"; }
    constructor(props, iModel) {
        super(props, iModel);
    }
    /** @beta */
    static deserialize(props) {
        const elProps = super.deserialize(props);
        const displayOptions = props.options?.element?.displayStyle;
        // Uncompress excludedElements if they are compressed
        if (!displayOptions?.compressExcludedElementIds && elProps.jsonProperties?.styles?.excludedElements) {
            const excludedElements = elProps.jsonProperties.styles.excludedElements;
            if (typeof excludedElements === "string" && excludedElements.startsWith("+")) {
                const ids = [];
                core_bentley_1.CompressedId64Set.decompressSet(excludedElements).forEach((id) => {
                    ids.push(id);
                });
                elProps.jsonProperties.styles.excludedElements = ids;
            }
        }
        // Omit Schedule Script Element Ids if the option is set
        if (displayOptions?.omitScheduleScriptElementIds && elProps.jsonProperties?.styles?.scheduleScript) {
            const scheduleScript = elProps.jsonProperties.styles.scheduleScript;
            elProps.jsonProperties.styles.scheduleScript = core_common_1.RenderSchedule.Script.removeScheduleScriptElementIds(scheduleScript);
        }
        return elProps;
    }
    /** @beta */
    static serialize(props, iModel) {
        const inst = super.serialize(props, iModel);
        return inst;
    }
    /** Create a Code for a DisplayStyle given a name that is meant to be unique within the scope of the specified DefinitionModel.
     * @param iModel  The IModelDb
     * @param scopeModelId The Id of the DefinitionModel that contains the DisplayStyle and provides the scope for its name.
     * @param codeValue The DisplayStyle name
     */
    static createCode(iModel, scopeModelId, codeValue) {
        const codeSpec = iModel.codeSpecs.getByName(core_common_1.BisCodeSpec.displayStyle);
        return new core_common_1.Code({ spec: codeSpec.id, scope: scopeModelId, value: codeValue });
    }
    collectReferenceIds(referenceIds) {
        super.collectReferenceIds(referenceIds);
        for (const [id] of this.settings.subCategoryOverrides) {
            referenceIds.addElement(id);
        }
        for (const excludedElementId of this.settings.excludedElementIds)
            referenceIds.addElement(excludedElementId);
        if (this.settings.renderTimeline) {
            referenceIds.addElement(this.settings.renderTimeline);
        }
        else {
            const script = this.loadScheduleScript();
            if (script)
                script.script.discloseIds(referenceIds);
        }
    }
    /** @alpha */
    static async onCloned(context, sourceElementProps, targetElementProps) {
        await super.onCloned(context, sourceElementProps, targetElementProps);
        if (!context.isBetweenIModels || !targetElementProps.jsonProperties?.styles)
            return;
        const settings = targetElementProps.jsonProperties.styles;
        if (settings.subCategoryOvr) {
            const targetOverrides = [];
            for (const ovr of settings.subCategoryOvr) {
                ovr.subCategory;
                const targetSubCategoryId = context.findTargetElementId(core_bentley_1.Id64.fromJSON(ovr.subCategory));
                if (core_bentley_1.Id64.isValid(targetSubCategoryId))
                    targetOverrides.push({ ...ovr, subCategory: targetSubCategoryId });
            }
            settings.subCategoryOvr = targetOverrides;
        }
        if (settings.excludedElements) {
            const excluded = "string" === typeof settings.excludedElements ? core_bentley_1.CompressedId64Set.decompressArray(settings.excludedElements) : settings.excludedElements;
            const excludedTargetElements = [];
            for (const excludedElement of excluded) {
                const remapped = context.findTargetElementId(excludedElement);
                if (core_bentley_1.Id64.isValid(remapped))
                    excludedTargetElements.push(remapped);
            }
            if (0 === excludedTargetElements.length)
                delete settings.excludedElements;
            else
                settings.excludedElements = core_bentley_1.CompressedId64Set.compressIds(core_bentley_1.OrderedId64Iterable.sortArray(excludedTargetElements));
        }
        if (settings.renderTimeline) {
            const renderTimeline = context.findTargetElementId(settings.renderTimeline);
            if (core_bentley_1.Id64.isValid(renderTimeline))
                settings.renderTimeline = renderTimeline;
            else
                delete settings.renderTimeline;
        }
        else if (settings.scheduleScript) {
            const scheduleScript = Element_1.RenderTimeline.remapScript(context, settings.scheduleScript);
            if (scheduleScript.length > 0)
                settings.scheduleScript = scheduleScript;
            else
                delete settings.scheduleScript;
        }
    }
    loadScheduleScript() {
        let script;
        let sourceId;
        if (this.settings.renderTimeline) {
            const timeline = this.iModel.elements.tryGetElement(this.settings.renderTimeline);
            if (timeline) {
                script = core_common_1.RenderSchedule.Script.fromJSON(timeline.scriptProps);
                sourceId = timeline.id;
            }
        }
        else if (this.settings.scheduleScriptProps) {
            script = core_common_1.RenderSchedule.Script.fromJSON(this.settings.scheduleScriptProps);
            sourceId = this.id;
        }
        return undefined !== sourceId && undefined !== script ? new core_common_1.RenderSchedule.ScriptReference(sourceId, script) : undefined;
    }
}
exports.DisplayStyle = DisplayStyle;
/** A DisplayStyle for 2d views.
 * @public @preview
 */
class DisplayStyle2d extends DisplayStyle {
    static get className() { return "DisplayStyle2d"; }
    _settings;
    get settings() { return this._settings; }
    constructor(props, iModel) {
        super(props, iModel);
        this._settings = new core_common_1.DisplayStyleSettings(this.jsonProperties);
    }
    /** Create a DisplayStyle2d for use by a ViewDefinition.
     * @param iModelDb The iModel
     * @param definitionModelId The [[DefinitionModel]]
     * @param name The name/CodeValue of the DisplayStyle2d
     * @returns The newly constructed DisplayStyle2d element.
     * @throws [[IModelError]] if unable to create the element.
     */
    static create(iModelDb, definitionModelId, name) {
        const displayStyleProps = {
            classFullName: this.classFullName,
            code: this.createCode(iModelDb, definitionModelId, name),
            model: definitionModelId,
            isPrivate: false,
            jsonProperties: {
                styles: {
                    backgroundColor: 0,
                    monochromeColor: core_common_1.ColorDef.white.toJSON(),
                    viewflags: core_common_1.ViewFlags.defaults,
                },
            },
        };
        return new DisplayStyle2d(displayStyleProps, iModelDb);
    }
    static insert(txnOrDb, definitionModelId, name) {
        const txn = txnOrDb instanceof EditTxn_1.EditTxn ? txnOrDb : txnOrDb[Symbols_1._implicitTxn];
        const displayStyle = this.create(txn.iModel, definitionModelId, name);
        return displayStyle.insert(txn);
    }
}
exports.DisplayStyle2d = DisplayStyle2d;
/** A DisplayStyle for 3d views.
 * See [how to create a DisplayStyle3d]($docs/learning/backend/CreateElements.md#DisplayStyle3d).
 * @public @preview
 */
class DisplayStyle3d extends DisplayStyle {
    static get className() { return "DisplayStyle3d"; }
    _settings;
    get settings() { return this._settings; }
    constructor(props, iModel) {
        super(props, iModel);
        this._settings = new core_common_1.DisplayStyle3dSettings(this.jsonProperties);
    }
    collectReferenceIds(referenceIds) {
        super.collectReferenceIds(referenceIds);
        for (const textureId of this.settings.environment.sky.textureIds)
            referenceIds.addElement(textureId);
        if (this.settings.planProjectionSettings)
            for (const planProjectionSetting of this.settings.planProjectionSettings)
                referenceIds.addElement(planProjectionSetting[0]);
        const groups = this.settings.contours.groups;
        for (const group of groups) {
            const subCategories = group.subCategories;
            for (const subCategoryId of subCategories) {
                referenceIds.addElement(subCategoryId);
            }
        }
    }
    /** @alpha */
    static async onCloned(context, sourceElementProps, targetElementProps) {
        await super.onCloned(context, sourceElementProps, targetElementProps);
        if (context.isBetweenIModels) {
            const convertTexture = (id) => core_bentley_1.Id64.isValidId64(id) ? context.findTargetElementId(id) : id;
            const skyBoxImageProps = targetElementProps?.jsonProperties?.styles?.environment?.sky?.image;
            if (skyBoxImageProps?.texture && core_bentley_1.Id64.isValidId64(skyBoxImageProps.texture))
                skyBoxImageProps.texture = convertTexture(skyBoxImageProps.texture);
            if (skyBoxImageProps?.textures) {
                skyBoxImageProps.textures.front = convertTexture(skyBoxImageProps.textures.front);
                skyBoxImageProps.textures.back = convertTexture(skyBoxImageProps.textures.back);
                skyBoxImageProps.textures.left = convertTexture(skyBoxImageProps.textures.left);
                skyBoxImageProps.textures.right = convertTexture(skyBoxImageProps.textures.right);
                skyBoxImageProps.textures.top = convertTexture(skyBoxImageProps.textures.top);
                skyBoxImageProps.textures.bottom = convertTexture(skyBoxImageProps.textures.bottom);
            }
            if (targetElementProps?.jsonProperties?.styles?.planProjections) {
                const remappedPlanProjections = {};
                for (const entry of Object.entries(targetElementProps.jsonProperties.styles.planProjections)) {
                    const remappedModelId = context.findTargetElementId(entry[0]);
                    if (core_bentley_1.Id64.isValidId64(remappedModelId)) {
                        remappedPlanProjections[remappedModelId] = entry[1];
                    }
                }
                targetElementProps.jsonProperties.styles.planProjections = remappedPlanProjections;
            }
            const groups = targetElementProps?.jsonProperties?.styles?.contours?.groups;
            if (groups) {
                for (const group of groups) {
                    if (group.subCategories) {
                        const subCategories = core_bentley_1.CompressedId64Set.decompressArray(group.subCategories);
                        const remappedSubCategories = [];
                        for (const subCategoryId of subCategories) {
                            const remappedSubCategoryId = context.findTargetElementId(subCategoryId);
                            if (core_bentley_1.Id64.isValidId64(remappedSubCategoryId)) {
                                remappedSubCategories.push(remappedSubCategoryId);
                            }
                        }
                        group.subCategories = core_bentley_1.CompressedId64Set.sortAndCompress(remappedSubCategories);
                    }
                }
            }
        }
    }
    /** Create a DisplayStyle3d for use by a ViewDefinition.
     * @param iModelDb The iModel
     * @param definitionModelId The [[DefinitionModel]]
     * @param name The name/CodeValue of the DisplayStyle3d
     * @returns The newly constructed DisplayStyle3d element.
     * @throws [[IModelError]] if unable to create the element.
     */
    static create(iModelDb, definitionModelId, name, options) {
        options = options ?? {};
        let viewflags = options.viewFlags?.toJSON();
        if (!viewflags)
            viewflags = options.viewflags ?? new core_common_1.ViewFlags().toJSON();
        const backgroundColor = options.backgroundColor instanceof core_common_1.ColorDef ? options.backgroundColor.toJSON() : options.backgroundColor;
        const settings = {
            ...options,
            viewflags,
            backgroundColor,
        };
        const displayStyleProps = {
            classFullName: this.classFullName,
            code: this.createCode(iModelDb, definitionModelId, name),
            model: definitionModelId,
            jsonProperties: { styles: settings },
            isPrivate: false,
        };
        return new DisplayStyle3d(displayStyleProps, iModelDb);
    }
    static insert(txnOrDb, definitionModelId, name, options) {
        const txn = txnOrDb instanceof EditTxn_1.EditTxn ? txnOrDb : txnOrDb[Symbols_1._implicitTxn];
        const displayStyle = this.create(txn.iModel, definitionModelId, name, options);
        return displayStyle.insert(txn);
    }
}
exports.DisplayStyle3d = DisplayStyle3d;
//# sourceMappingURL=DisplayStyle.js.map