"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 IModelComponents
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.CategoryVisibilityHandler = exports.loadCategoriesFromViewport = exports.useCategories = void 0;
/* eslint-disable deprecation/deprecation */
const React = require("react");
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const core_frontend_1 = require("@itwin/core-frontend");
const presentation_common_1 = require("@itwin/presentation-common");
const components_react_1 = require("@itwin/components-react");
const EMPTY_CATEGORIES_ARRAY = [];
/**
 * Loads categories from viewport or uses provided list of categories.
 * @internal
 */
function useCategories(viewManager, imodel, view) {
    var _a;
    const currentView = view || viewManager.getFirstOpenView();
    const categoriesPromise = React.useMemo(async () => loadCategoriesFromViewport(imodel, currentView), [imodel, currentView]);
    return (_a = (0, components_react_1.useAsyncValue)(categoriesPromise)) !== null && _a !== void 0 ? _a : EMPTY_CATEGORIES_ARRAY;
}
exports.useCategories = useCategories;
/** @internal */
async function loadCategoriesFromViewport(iModel, vp) {
    if (!vp)
        return EMPTY_CATEGORIES_ARRAY;
    // Query categories and add them to state
    const selectUsedSpatialCategoryIds = "SELECT DISTINCT Category.Id as id from BisCore.GeometricElement3d WHERE Category.Id IN (SELECT ECInstanceId from BisCore.SpatialCategory)";
    const selectUsedDrawingCategoryIds = "SELECT DISTINCT Category.Id as id from BisCore.GeometricElement2d WHERE Model.Id=? AND Category.Id IN (SELECT ECInstanceId from BisCore.DrawingCategory)";
    const ecsql = vp.view.is3d() ? selectUsedSpatialCategoryIds : selectUsedDrawingCategoryIds;
    const ecsql2 = `SELECT ECInstanceId as id, UserLabel as label, CodeValue as code FROM ${vp.view.is3d() ? "BisCore.SpatialCategory" : "BisCore.DrawingCategory"} WHERE ECInstanceId IN (${ecsql})`;
    const categories = [];
    // istanbul ignore else
    if (iModel) {
        const rowIterator = iModel.query(ecsql2, undefined, { rowFormat: core_common_1.QueryRowFormat.UseJsPropertyNames });
        // istanbul ignore next
        for await (const row of rowIterator) {
            const subCategoryIds = iModel.subcategories.getSubCategories(row.id);
            categories.push({ key: row.id, children: (subCategoryIds) ? [...subCategoryIds] : undefined });
        }
    }
    return categories;
}
exports.loadCategoriesFromViewport = loadCategoriesFromViewport;
/**
 * @alpha
 * @deprecated in 3.6. Was moved to `@itwin/tree-widget-react` package.
 */
class CategoryVisibilityHandler {
    constructor(params) {
        var _a;
        this.onVisibilityChange = new core_bentley_1.BeEvent();
        // eslint-disable-next-line @typescript-eslint/naming-convention
        this.onDisplayStyleChanged = () => {
            this.onVisibilityChangeInternal();
        };
        // eslint-disable-next-line @typescript-eslint/naming-convention
        this.onViewedCategoriesChanged = () => {
            this.onVisibilityChangeInternal();
        };
        this._viewManager = params.viewManager;
        this._imodel = params.imodel;
        this._activeView = params.activeView;
        // istanbul ignore next
        this._useAllViewports = (_a = params.allViewports) !== null && _a !== void 0 ? _a : false;
        this._categories = params.categories;
        if (this._activeView) {
            this._activeView.onDisplayStyleChanged.addListener(this.onDisplayStyleChanged);
            this._activeView.onViewedCategoriesChanged.addListener(this.onViewedCategoriesChanged);
        }
    }
    dispose() {
        if (this._activeView) {
            this._activeView.onDisplayStyleChanged.removeListener(this.onDisplayStyleChanged);
            this._activeView.onViewedCategoriesChanged.removeListener(this.onViewedCategoriesChanged);
        }
        clearTimeout(this._pendingVisibilityChange);
    }
    getVisibilityStatus(node, nodeKey) {
        const instanceId = CategoryVisibilityHandler.getInstanceIdFromTreeNodeKey(nodeKey);
        return { state: node.parentId ? this.getSubCategoryVisibility(instanceId) : this.getCategoryVisibility(instanceId) };
    }
    async changeVisibility(node, nodeKey, shouldDisplay) {
        var _a;
        // handle subcategory visibility change
        if (node.parentId) {
            const childId = CategoryVisibilityHandler.getInstanceIdFromTreeNodeKey(nodeKey);
            // istanbul ignore next
            const parentId = (_a = this.getParent(childId)) === null || _a === void 0 ? void 0 : _a.key;
            // make sure parent category is enabled
            if (shouldDisplay && parentId)
                CategoryVisibilityHandler.enableCategory(this._viewManager, this._imodel, [parentId], true, this._useAllViewports, false);
            CategoryVisibilityHandler.enableSubCategory(this._viewManager, childId, shouldDisplay, this._useAllViewports);
            return;
        }
        const instanceId = CategoryVisibilityHandler.getInstanceIdFromTreeNodeKey(nodeKey);
        CategoryVisibilityHandler.enableCategory(this._viewManager, this._imodel, [instanceId], shouldDisplay, true);
    }
    getSubCategoryVisibility(id) {
        const parentItem = this.getParent(id);
        if (!parentItem || !this._activeView)
            return "hidden";
        const isVisible = this._activeView.view.viewsCategory(parentItem.key) && this._activeView.isSubCategoryVisible(id);
        return isVisible ? "visible" : "hidden";
    }
    getCategoryVisibility(id) {
        if (!this._activeView)
            return "hidden";
        return this._activeView.view.viewsCategory(id) ? "visible" : "hidden";
    }
    getParent(key) {
        for (const category of this._categories) {
            // istanbul ignore else
            if (category.children) {
                if (category.children.indexOf(key) !== -1)
                    return category;
            }
        }
        return undefined;
    }
    onVisibilityChangeInternal() {
        if (this._pendingVisibilityChange)
            return;
        this._pendingVisibilityChange = setTimeout(() => {
            this.onVisibilityChange.raiseEvent();
            this._pendingVisibilityChange = undefined;
        }, 0);
    }
    static getInstanceIdFromTreeNodeKey(nodeKey) {
        return (presentation_common_1.NodeKey.isInstancesNodeKey(nodeKey) && nodeKey.instanceKeys.length > 0) ? nodeKey.instanceKeys[0].id : /* istanbul ignore next */ "";
    }
    /** Changes category display in the viewport */
    static enableCategory(viewManager, imodel, ids, enabled, forAllViewports, enableAllSubCategories = true) {
        if (!viewManager.selectedView)
            return;
        const updateViewport = (vp) => {
            // Only act on viewports that are both 3D or both 2D. Important if we have multiple viewports opened and we
            // are using 'allViewports' property
            if (viewManager.selectedView && viewManager.selectedView.view.is3d() === vp.view.is3d()) {
                vp.changeCategoryDisplay(ids, enabled, enableAllSubCategories);
                // remove category overrides per model
                const modelsContainingOverrides = [];
                for (const ovr of vp.perModelCategoryVisibility) {
                    // istanbul ignore else
                    if (ids.findIndex((id) => id === ovr.categoryId) !== -1)
                        modelsContainingOverrides.push(ovr.modelId);
                }
                vp.perModelCategoryVisibility.setOverride(modelsContainingOverrides, ids, core_frontend_1.PerModelCategoryVisibility.Override.None);
                // changeCategoryDisplay only enables subcategories, it does not disabled them. So we must do that ourselves.
                if (false === enabled) {
                    ids.forEach((id) => {
                        const subCategoryIds = imodel.subcategories.getSubCategories(id);
                        // istanbul ignore else
                        if (subCategoryIds) {
                            subCategoryIds.forEach((subCategoryId) => CategoryVisibilityHandler.enableSubCategory(viewManager, subCategoryId, false, forAllViewports));
                        }
                    });
                }
            }
        };
        // This property let us act on all viewports or just on the selected one, configurable by the app
        if (forAllViewports) {
            for (const viewport of viewManager) {
                updateViewport(viewport);
            }
        }
        else {
            updateViewport(viewManager.selectedView);
        }
    }
    /** Changes subcategory display in the viewport */
    static enableSubCategory(viewManager, key, enabled, forAllViewports) {
        if (!viewManager.selectedView)
            return;
        const updateViewport = (vp) => {
            // Only act on viewports that are both 3D or both 2D. Important if we have multiple viewports opened and we
            // are using 'allViewports' property
            if (viewManager.selectedView && viewManager.selectedView.view.is3d() === vp.view.is3d()) {
                vp.changeSubCategoryDisplay(key, enabled);
            }
        };
        // This property let us act on all viewports or just on the selected one, configurable by the app
        if (forAllViewports) {
            for (const viewport of viewManager) {
                updateViewport(viewport);
            }
        }
        else {
            updateViewport(viewManager.selectedView);
        }
    }
}
exports.CategoryVisibilityHandler = CategoryVisibilityHandler;
//# sourceMappingURL=CategoryVisibilityHandler.js.map