"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.VisibilityTreeEventHandler = void 0;
/* eslint-disable deprecation/deprecation */
const empty_1 = require("rxjs/internal/observable/empty");
const from_1 = require("rxjs/internal/observable/from");
const map_1 = require("rxjs/internal/operators/map");
const mergeMap_1 = require("rxjs/internal/operators/mergeMap");
const components_react_1 = require("@itwin/components-react");
const core_react_1 = require("@itwin/core-react");
const presentation_components_1 = require("@itwin/presentation-components");
/**
 * Base event handler for visibility tree.
 * @alpha
 * @deprecated in 3.6. Was moved to `@itwin/tree-widget-react` package.
 */
class VisibilityTreeEventHandler extends presentation_components_1.UnifiedSelectionTreeEventHandler {
    constructor(params) {
        super(params);
        this._listeners = new Array();
        this._visibilityHandler = params.visibilityHandler;
        this._selectionPredicate = params.selectionPredicate;
        if (this._visibilityHandler) {
            this._listeners.push(this._visibilityHandler.onVisibilityChange.addListener(async (nodeIds, visibilityStatus) => this.updateCheckboxes(nodeIds, visibilityStatus)));
        }
        this._listeners.push(this.modelSource.onModelChanged.addListener(async ([_, changes]) => this.updateCheckboxes([...changes.addedNodeIds, ...changes.modifiedNodeIds])));
        this.updateCheckboxes(); // eslint-disable-line @typescript-eslint/no-floating-promises
    }
    dispose() {
        super.dispose();
        this._listeners.forEach((disposeFunc) => disposeFunc());
    }
    filterSelectionItems(items) {
        // istanbul ignore if
        if (!this._selectionPredicate)
            return items;
        return items.filter((item) => this._selectionPredicate(this.getNodeKey(item), item));
    }
    onSelectionModified({ modifications }) {
        const filteredModification = (0, components_react_1.toRxjsObservable)(modifications).pipe((0, map_1.map)(({ selectedNodeItems, deselectedNodeItems }) => {
            return {
                selectedNodeItems: this.filterSelectionItems(selectedNodeItems),
                deselectedNodeItems: this.filterSelectionItems(deselectedNodeItems),
            };
        }));
        return super.onSelectionModified({ modifications: filteredModification });
    }
    onSelectionReplaced({ replacements }) {
        const filteredReplacements = (0, components_react_1.toRxjsObservable)(replacements).pipe((0, map_1.map)(({ selectedNodeItems }) => {
            return {
                selectedNodeItems: this.filterSelectionItems(selectedNodeItems),
            };
        }));
        return super.onSelectionReplaced({ replacements: filteredReplacements });
    }
    onCheckboxStateChanged(event) {
        // istanbul ignore if
        if (!this._visibilityHandler)
            return undefined;
        (0, from_1.from)(event.stateChanges)
            .pipe((0, mergeMap_1.mergeMap)((changes) => this.changeVisibility(changes)))
            .subscribe();
        return undefined;
    }
    changeVisibility(changes) {
        return (0, from_1.from)(changes)
            .pipe((0, mergeMap_1.mergeMap)(({ nodeItem, newState }) => {
            // istanbul ignore if
            if (!this._visibilityHandler)
                return empty_1.EMPTY;
            return (0, from_1.from)(this._visibilityHandler.changeVisibility(nodeItem, this.getNodeKey(nodeItem), newState === core_react_1.CheckBoxState.On));
        }));
    }
    async updateCheckboxes(affectedNodes, visibilityStatus) {
        const changes = await (affectedNodes ? this.collectAffectedNodesCheckboxInfos(affectedNodes, visibilityStatus) : this.collectAllNodesCheckboxInfos(visibilityStatus));
        this.updateModel(changes);
    }
    updateModel(changes) {
        this.modelSource.modifyModel((model) => {
            for (const [nodeId, checkboxInfo] of changes) {
                const node = model.getNode(nodeId);
                // istanbul ignore if
                if (!node)
                    continue;
                node.checkbox.isDisabled = checkboxInfo.isDisabled;
                node.checkbox.isVisible = checkboxInfo.isVisible;
                node.checkbox.state = checkboxInfo.state;
                node.checkbox.tooltip = checkboxInfo.tooltip;
            }
        });
    }
    async collectAffectedNodesCheckboxInfos(affectedNodes, visibilityStatus) {
        const nodeStates = new Map();
        if (affectedNodes.length === 0)
            return nodeStates;
        await Promise.all(affectedNodes.map(async (nodeId) => {
            const node = this.modelSource.getModel().getNode(nodeId);
            // istanbul ignore else
            if (node)
                nodeStates.set(nodeId, await this.getNodeCheckBoxInfo(node, visibilityStatus));
        }));
        return nodeStates;
    }
    async collectAllNodesCheckboxInfos(visibilityStatus) {
        const nodeStates = new Map();
        for (const node of this.modelSource.getModel().iterateTreeModelNodes()) {
            nodeStates.set(node.id, await this.getNodeCheckBoxInfo(node, visibilityStatus));
        }
        return nodeStates;
    }
    async getNodeCheckBoxInfo(node, visibilityStatus) {
        var _a;
        if (!this._visibilityHandler)
            return { ...node.checkbox, isVisible: false };
        const result = (_a = visibilityStatus === null || visibilityStatus === void 0 ? void 0 : visibilityStatus.get(node.id)) !== null && _a !== void 0 ? _a : this._visibilityHandler.getVisibilityStatus(node.item, this.getNodeKey(node.item));
        if ((0, core_react_1.isPromiseLike)(result))
            return this.createCheckboxInfo(await result);
        return this.createCheckboxInfo(result);
    }
    createCheckboxInfo(status) {
        return {
            state: visibilityStateToCheckboxState(status),
            isDisabled: status.isDisabled || false,
            isVisible: true,
            tooltip: status.tooltip,
        };
    }
}
exports.VisibilityTreeEventHandler = VisibilityTreeEventHandler;
const visibilityStateToCheckboxState = (status) => {
    switch (status.state) {
        case "visible":
            return core_react_1.CheckBoxState.On;
        // istanbul ignore next
        case "partial":
            return core_react_1.CheckBoxState.Partial;
        case "hidden":
        default:
            return core_react_1.CheckBoxState.Off;
    }
};
//# sourceMappingURL=VisibilityTreeEventHandler.js.map