"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 iModels
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.SpatialCategory = exports.DrawingCategory = exports.Category = exports.SubCategory = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const Element_1 = require("./Element");
const IModelDb_1 = require("./IModelDb");
const NavigationRelationship_1 = require("./NavigationRelationship");
/** Defines the appearance for graphics in Geometric elements
 * @public @preview
 */
class SubCategory extends Element_1.DefinitionElement {
    static get className() { return "SubCategory"; }
    /** The Appearance parameters for this SubCategory */
    appearance;
    /** Optional description of this SubCategory. */
    description;
    constructor(props, iModel) {
        super(props, iModel);
        this.appearance = new core_common_1.SubCategoryAppearance(props.appearance);
        this.description = core_bentley_1.JsonUtils.asString(props.description);
    }
    /**
     * SubCategory custom HandledProps include 'description' and 'properties'.
     * @inheritdoc
     * @beta
     */
    static _customHandledProps = [
        { propertyName: "description", source: "Class" },
        { propertyName: "properties", source: "Class" },
    ];
    /**
     * SubCategory deserializes 'description' and 'properties'.
     * @inheritdoc
     * @beta
     */
    static deserialize(props) {
        const elProps = super.deserialize(props);
        elProps.description = core_bentley_1.JsonUtils.asString(props.row.description);
        if (props.row.properties !== '') {
            elProps.appearance = JSON.parse(props.row.properties);
        }
        else {
            elProps.appearance = undefined;
        }
        return elProps;
    }
    /**
     * SubCategory serialize 'description' and 'properties'.
     * @inheritdoc
     * @beta
     */
    static serialize(props, iModel) {
        const inst = super.serialize(props, iModel);
        if (props.description !== undefined) {
            inst.description = props.description;
        }
        if (props.appearance !== undefined) {
            inst.properties = JSON.stringify(props.appearance);
        }
        return inst;
    }
    toJSON() {
        const val = super.toJSON();
        val.appearance = this.appearance.toJSON();
        if (this.description && this.description.length > 0)
            val.description = this.description;
        return val;
    }
    /** Get the SubCategory's name (its Code value). */
    getSubCategoryName() { return this.code.value; }
    /** Get the Id of the SubCategory. */
    getSubCategoryId() { return this.id; }
    /** Get the Id of this SubCategory's parent Category. */
    getCategoryId() { return this.parent ? this.parent.id : core_bentley_1.Id64.invalid; }
    /** Check if this is the default SubCategory of its parent Category. */
    get isDefaultSubCategory() { return IModelDb_1.IModelDb.getDefaultSubCategoryId(this.getCategoryId()) === this.getSubCategoryId(); }
    /** Create a Code for a SubCategory given a name that is meant to be unique within the scope of the specified parent Category.
     * @param iModel  The IModel
     * @param parentCategoryId The Id of the parent Category that owns the SubCategory and provides the scope for its name.
     * @param codeValue The name of the SubCategory
     */
    static createCode(iModel, parentCategoryId, codeValue) {
        const codeSpec = iModel.codeSpecs.getByName(core_common_1.BisCodeSpec.subCategory);
        return new core_common_1.Code({ spec: codeSpec.id, scope: parentCategoryId, value: codeValue });
    }
    /** Create a new SubCategory
     * @param iModelDb The iModel
     * @param parentCategoryId Create the new SubCategory as a child of this [[Category]]
     * @param name The name of the SubCategory
     * @param appearance The appearance settings to use for this SubCategory
     * @returns The newly constructed SubCategory element.
     * @throws [[IModelError]] if unable to create the element.
     */
    static create(iModelDb, parentCategoryId, name, appearance) {
        if (appearance instanceof core_common_1.SubCategoryAppearance)
            appearance = appearance.toJSON();
        const parentCategory = iModelDb.elements.getElement(parentCategoryId);
        const subCategoryProps = {
            classFullName: this.classFullName,
            model: parentCategory.model,
            parent: new NavigationRelationship_1.CategoryOwnsSubCategories(parentCategoryId),
            code: this.createCode(iModelDb, parentCategoryId, name),
            appearance,
        };
        return new SubCategory(subCategoryProps, iModelDb);
    }
    /** Insert a new SubCategory
     * @param iModelDb Insert into this iModel
     * @param parentCategoryId Insert the new SubCategory as a child of this Category
     * @param name The name of the SubCategory
     * @param appearance The appearance settings to use for this SubCategory
     * @returns The Id of the newly inserted SubCategory element.
     * @throws [[IModelError]] if unable to insert the element.
     */
    static insert(iModelDb, parentCategoryId, name, appearance) {
        const subCategory = this.create(iModelDb, parentCategoryId, name, appearance);
        return iModelDb.elements.insertElement(subCategory.toJSON());
    }
}
exports.SubCategory = SubCategory;
/** A Category element is the target of the `category` member of [[GeometricElement]].
 * @public @preview
 */
class Category extends Element_1.DefinitionElement {
    static get className() { return "Category"; }
    rank = core_common_1.Rank.User;
    description;
    constructor(props, iModel) {
        super(props, iModel);
        this.rank = core_bentley_1.JsonUtils.asInt(props.rank);
        this.description = core_bentley_1.JsonUtils.asString(props.description);
    }
    /**
     * Category custom HandledProps include 'rank' and 'description'.
     * @inheritdoc
     * @beta
     */
    static _customHandledProps = [
        { propertyName: "rank", source: "Class" },
        { propertyName: "description", source: "Class" },
    ];
    /**
     * Category deserializes 'rank' and 'description'.
     * @inheritdoc
     * @beta
     */
    static deserialize(props) {
        const elProps = super.deserialize(props);
        elProps.description = core_bentley_1.JsonUtils.asString(props.row.description);
        elProps.rank = core_bentley_1.JsonUtils.asInt(props.row.rank);
        return elProps;
    }
    /**
     * Category serialize 'rank' and 'description'.
     * @inheritdoc
     * @beta
     */
    static serialize(props, iModel) {
        const inst = super.serialize(props, iModel);
        if (undefined !== props.description) {
            inst.description = props.description;
        }
        inst.rank = props.rank;
        return inst;
    }
    toJSON() {
        const val = super.toJSON();
        val.rank = this.rank;
        if (this.description && this.description.length > 0)
            val.description = this.description;
        return val;
    }
    /** Get the Id of the default SubCategory for this Category. */
    myDefaultSubCategoryId() { return IModelDb_1.IModelDb.getDefaultSubCategoryId(this.id); }
    /** Set the appearance of the default SubCategory for this Category */
    setDefaultAppearance(props) {
        if (props instanceof core_common_1.SubCategoryAppearance)
            props = props.toJSON();
        const subCat = this.iModel.elements.getElement(this.myDefaultSubCategoryId());
        subCat.appearance = new core_common_1.SubCategoryAppearance(props);
        this.iModel.elements.updateElement(subCat.toJSON());
    }
}
exports.Category = Category;
/** Categorizes 2d GeometricElements.
 * @public @preview
 */
class DrawingCategory extends Category {
    static get className() { return "DrawingCategory"; }
    constructor(opts, iModel) { super(opts, iModel); }
    /** Get the name of the CodeSpec that is used by DrawingCategory objects. */
    static getCodeSpecName() { return core_common_1.BisCodeSpec.drawingCategory; }
    /** Looks up the CategoryId of a DrawingCategory by model and name */
    static queryCategoryIdByName(iModel, scopeModelId, categoryName) {
        const code = DrawingCategory.createCode(iModel, scopeModelId, categoryName);
        return iModel.elements.queryElementIdByCode(code);
    }
    /** Create a Code for a DrawingCategory given a name that is meant to be unique within the scope of the specified DefinitionModel.
     * @param iModel  The IModel
     * @param scopeModelId The Id of the DefinitionModel that contains the DrawingCategory and provides the scope for its name.
     * @param codeValue The name of the category
     * @return A drawing category Code
     */
    static createCode(iModel, scopeModelId, codeValue) {
        const codeSpec = iModel.codeSpecs.getByName(DrawingCategory.getCodeSpecName());
        return new core_common_1.Code({ spec: codeSpec.id, scope: scopeModelId, value: codeValue });
    }
    /** Create a new DrawingCategory
     * @param iModelDb The iModel
     * @param definitionModelId The [[DefinitionModel]]
     * @param name The name of the DrawingCategory
     * @returns The newly constructed DrawingCategory element.
     * @throws [[IModelError]] if unable to create the element.
     */
    static create(iModelDb, definitionModelId, name) {
        const categoryProps = {
            classFullName: this.classFullName,
            model: definitionModelId,
            code: this.createCode(iModelDb, definitionModelId, name),
            isPrivate: false,
        };
        return new DrawingCategory(categoryProps, iModelDb);
    }
    /** Insert a new DrawingCategory
     * @param iModelDb Insert into this iModel
     * @param definitionModelId Insert the new DrawingCategory into this [[DefinitionModel]]
     * @param name The name of the DrawingCategory
     * @param defaultAppearance The appearance settings to use for the default SubCategory of this DrawingCategory
     * @returns The Id of the newly inserted DrawingCategory element.
     * @throws [[IModelError]] if unable to insert the element.
     */
    static insert(iModelDb, definitionModelId, name, defaultAppearance) {
        const category = this.create(iModelDb, definitionModelId, name);
        const elements = iModelDb.elements;
        category.id = elements.insertElement(category.toJSON());
        category.setDefaultAppearance(defaultAppearance);
        return category.id;
    }
}
exports.DrawingCategory = DrawingCategory;
/** Categorizes SpatialElements. See [how to create a SpatialCategory]($docs/learning/backend/CreateElements.md#SpatialCategory).
 * @public @preview
 */
class SpatialCategory extends Category {
    static get className() { return "SpatialCategory"; }
    constructor(opts, iModel) { super(opts, iModel); }
    /** Get the name of the CodeSpec that is used by SpatialCategory objects. */
    static getCodeSpecName() { return core_common_1.BisCodeSpec.spatialCategory; }
    /** Looks up the CategoryId of a SpatialCategory by model and name */
    static queryCategoryIdByName(iModel, scopeModelId, categoryName) {
        const code = SpatialCategory.createCode(iModel, scopeModelId, categoryName);
        return iModel.elements.queryElementIdByCode(code);
    }
    /** Create a Code for a SpatialCategory given a name that is meant to be unique within the scope of the specified DefinitionModel.
     * @param iModel  The IModel
     * @param scopeModelId The Id of the DefinitionModel that contains the SpatialCategory and provides the scope for its name.
     * @param codeValue The name of the category
     * @return A spatial category Code
     */
    static createCode(iModel, scopeModelId, codeValue) {
        const codeSpec = iModel.codeSpecs.getByName(SpatialCategory.getCodeSpecName());
        return new core_common_1.Code({ spec: codeSpec.id, scope: scopeModelId, value: codeValue });
    }
    /** Create a new SpatialCategory
     * @param iModelDb The iModel
     * @param definitionModelId The [[DefinitionModel]]
     * @param name The name/CodeValue of the SpatialCategory
     * @returns The newly constructed SpatialCategory element.
     * @throws [[IModelError]] if unable to create the element.
     */
    static create(iModelDb, definitionModelId, name) {
        const categoryProps = {
            classFullName: this.classFullName,
            model: definitionModelId,
            code: this.createCode(iModelDb, definitionModelId, name),
            isPrivate: false,
        };
        return new SpatialCategory(categoryProps, iModelDb);
    }
    /** Insert a new SpatialCategory
     * @param iModelDb Insert into this iModel
     * @param definitionModelId Insert the new SpatialCategory into this DefinitionModel
     * @param name The name of the SpatialCategory
     * @param defaultAppearance The appearance settings to use for the default SubCategory of this SpatialCategory
     * @returns The Id of the newly inserted SpatialCategory element.
     * @throws [[IModelError]] if unable to insert the element.
     */
    static insert(iModelDb, definitionModelId, name, defaultAppearance) {
        const category = this.create(iModelDb, definitionModelId, name);
        category.id = iModelDb.elements.insertElement(category.toJSON());
        category.setDefaultAppearance(defaultAppearance);
        return category.id;
    }
}
exports.SpatialCategory = SpatialCategory;
//# sourceMappingURL=Category.js.map