"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 Picker
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.IModelConnectedViewSelector = exports.ViewSelector = exports.ViewSelectorChangedEvent = void 0;
const React = require("react");
const core_bentley_1 = require("@itwin/core-bentley");
const core_frontend_1 = require("@itwin/core-frontend");
const appui_abstract_1 = require("@itwin/appui-abstract");
const connectIModel_1 = require("../redux/connectIModel");
const UiFramework_1 = require("../UiFramework");
const ViewUtilities_1 = require("../utils/ViewUtilities");
const ListPicker_1 = require("./ListPicker");
const lodash_1 = require("lodash");
/** ViewSelector Changed Event class.
 * @beta
 */
class ViewSelectorChangedEvent extends appui_abstract_1.UiEvent {
}
exports.ViewSelectorChangedEvent = ViewSelectorChangedEvent;
/** ViewSelector Show Update Event class.
 */
class ViewSelectorShowUpdateEvent extends appui_abstract_1.UiEvent {
}
/** View Selector React component
 * @beta
 */
class ViewSelector extends React.Component {
    /** Creates a ViewSelector */
    constructor(props) {
        super(props);
        this._isMounted = false;
        this._searchInput = "";
        this._handleViewSelectorShowUpdateEvent = (args) => {
            // istanbul ignore next
            if (!this._isMounted)
                return;
            this.setState(args, async () => this.loadViews());
        };
        // enable/disable the models
        // istanbul ignore next
        this._setEnabled = async (item, _enabled) => {
            const activeContentControl = UiFramework_1.UiFramework.content.getActiveContentControl();
            if (!activeContentControl || !activeContentControl.supportsViewSelectorChange) {
                core_bentley_1.Logger.logError(UiFramework_1.UiFramework.loggerCategory(this), `No active ContentControl for ViewSelector change`);
                return;
            }
            // Enable the item temporarily to let user see that their click was registered
            // while we query for view state and change the current view which may take a bit
            if (_enabled && item.type !== ListPicker_1.ListItemType.Container) {
                // This itemMapper simply looks through all the list items and their nested children and enables the one
                // that we have registered to enable
                // Also disable all other items
                const itemMapper = (tempItem) => {
                    if (tempItem.type === ListPicker_1.ListItemType.Container) {
                        return { ...tempItem, children: tempItem.children.map(itemMapper) };
                    }
                    else if (tempItem.key === item.key) {
                        return { ...tempItem, enabled: true };
                    }
                    else {
                        return { ...tempItem, enabled: false };
                    }
                };
                // Create the new array with the current item enabled
                const itemsWithEnabled = this.state.items.map(itemMapper);
                // istanbul ignore next
                if (!this._isMounted)
                    return;
                // Update the state so that we show the user it was enabled while we work in the background
                this.setState({ items: itemsWithEnabled });
            }
            // Load the view state using the viewSpec's ID
            const viewState = await this.props.imodel.views.load(item.key);
            // Let activeContentControl process the ViewSelector change
            await activeContentControl.processViewSelectorChange(this.props.imodel, item.key, viewState, item.name);
            // Emit a change event
            ViewSelector.onViewSelectorChangedEvent.emit({
                iModelConnection: this.props.imodel,
                viewDefinitionId: item.key,
                viewState,
                name: item.name,
            });
            // Set state to show enabled the view that got selected
            this.updateState(item.key); // eslint-disable-line @typescript-eslint/no-floating-promises
        };
        // Hook on the category selector being expanded so that we may initialize if needed
        // istanbul ignore next
        this._onExpanded = (expand) => {
            if (expand)
                this.updateState(core_frontend_1.IModelApp.viewManager.selectedView ? core_frontend_1.IModelApp.viewManager.selectedView.view.id : undefined); // eslint-disable-line @typescript-eslint/no-floating-promises
        };
        this.state = {
            items: new Array(),
            title: UiFramework_1.UiFramework.translate("viewTypes.views"),
            initialized: false,
            showSpatials: props.showSpatials,
            showDrawings: props.showDrawings,
            showSheets: props.showSheets,
            showUnknown: props.showUnknown,
            searchBox: props.searchBox ? props.searchBox : true,
        };
    }
    /** Updates the ViewSelector show settings.
     */
    static updateShowSettings(showSpatials, showDrawings, showSheets, showUnknown) {
        ViewSelector._onViewSelectorShowUpdateEvent.emit({ showSpatials, showDrawings, showSheets, showUnknown });
    }
    async componentDidMount() {
        this._isMounted = true;
        if (this.props.listenForShowUpdates)
            this._removeShowUpdateListener = ViewSelector._onViewSelectorShowUpdateEvent.addListener(this._handleViewSelectorShowUpdateEvent);
        await this.loadViews();
    }
    async componentDidUpdate(prevProps) {
        if (this.props.imodel !== prevProps.imodel) {
            await this.loadViews();
        }
    }
    componentWillUnmount() {
        this._isMounted = false;
        // istanbul ignore else
        if (this._removeShowUpdateListener)
            this._removeShowUpdateListener();
    }
    setStateContainers(views3d, views2d, sheets, unknown, views3dFiltered, views2dFiltered, sheetsFiltered, unknownFiltered) {
        const views3dContainer = {
            key: "views3dContainer",
            name: UiFramework_1.UiFramework.translate("viewTypes.spatialViews"),
            enabled: false,
            type: ListPicker_1.ListItemType.Container,
            children: views3dFiltered ? views3dFiltered : views3d,
        };
        const views2dContainer = {
            key: "views2dContainer",
            name: UiFramework_1.UiFramework.translate("viewTypes.drawings"),
            enabled: false,
            type: ListPicker_1.ListItemType.Container,
            children: views2dFiltered ? views2dFiltered : views2d,
        };
        const sheetContainer = {
            key: "sheetContainer",
            name: UiFramework_1.UiFramework.translate("viewTypes.sheets"),
            enabled: false,
            type: ListPicker_1.ListItemType.Container,
            children: sheetsFiltered ? sheetsFiltered : sheets,
        };
        const containers = [views3dContainer, views2dContainer, sheetContainer];
        // istanbul ignore if
        if (unknown && unknown.length > 0) {
            // This should never show, but just in case we missed a type of view state
            const unknownContainer = {
                key: "unknownContainer",
                name: UiFramework_1.UiFramework.translate("viewTypes.others"),
                enabled: false,
                type: ListPicker_1.ListItemType.Container,
                children: unknownFiltered ? unknownFiltered : unknown,
            };
            if (unknown.length !== 0)
                containers.push(unknownContainer);
        }
        // istanbul ignore next
        if (!this._isMounted)
            return;
        this.setState({
            items: containers,
            title: UiFramework_1.UiFramework.translate("viewTypes.views"),
            initialized: true,
        });
    }
    /**
     * Query the views and set the initial state with the iModel's views.
     */
    async loadViews() {
        // Query views and add them to state
        const views3d = [];
        const views2d = [];
        const sheets = [];
        const unknown = [];
        let views3dFiltered;
        let views2dFiltered;
        let sheetsFiltered;
        let unknownFiltered;
        // istanbul ignore if
        if (this.props.imodel && this.props.imodel.views.getViewList) {
            const query = { wantPrivate: false };
            const specs = await this.props.imodel.views.getViewList(query);
            specs.forEach((spec) => {
                const viewItem = {
                    key: spec.id,
                    name: spec.name,
                    enabled: false,
                    type: ListPicker_1.ListItemType.Item,
                };
                const className = ViewUtilities_1.ViewUtilities.getBisBaseClass(spec.class);
                if (ViewUtilities_1.ViewUtilities.isSpatial(className) && this.state.showSpatials)
                    views3d.push(viewItem);
                else if (ViewUtilities_1.ViewUtilities.isDrawing(className) && this.state.showDrawings)
                    views2d.push(viewItem);
                else if (ViewUtilities_1.ViewUtilities.isSheet(className) && this.state.showSheets)
                    sheets.push(viewItem);
                else if (this.state.showUnknown)
                    unknown.push(viewItem);
            });
            if (this._searchInput.length > 0) {
                views3dFiltered = views3d.filter((view) => { var _a; return (_a = view.name) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(this._searchInput.toLowerCase()); });
                views2dFiltered = views2d.filter((view) => { var _a; return (_a = view.name) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(this._searchInput.toLowerCase()); });
                sheetsFiltered = sheets.filter((view) => { var _a; return (_a = view.name) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(this._searchInput.toLowerCase()); });
                unknownFiltered = unknown.filter((view) => { var _a; return (_a = view.name) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes(this._searchInput.toLowerCase()); });
            }
        }
        this.setStateContainers(views3d, views2d, sheets, unknown, views3dFiltered, views2dFiltered, sheetsFiltered, unknownFiltered);
    }
    /**
     * Update state of the entries in the widget.
     * @param viewId Identifier for the relevant view
     */
    // istanbul ignore next
    async updateState(viewId) {
        // Wait for initialization finished
        if (!this.state.initialized)
            return;
        // Query views and add them to state
        const views3d = this.state.items[0].children;
        const views2d = this.state.items[1].children;
        const sheets = this.state.items[2].children;
        const unknown = this.state.items.length > 3 ? this.state.items[3].children : [];
        const updateChildren = (item) => {
            if (item.key === viewId)
                return { ...item, enabled: true };
            else
                return { ...item, enabled: false };
        };
        this.setStateContainers(views3d.map(updateChildren), views2d.map(updateChildren), sheets.map(updateChildren), unknown.map(updateChildren));
    }
    /**
     *  Renders ViewSelector component
     */
    render() {
        if (!this.state.initialized)
            return null;
        const { imodel, ...props } = this.props; // eslint-disable-line @typescript-eslint/no-unused-vars
        return (React.createElement(ListPicker_1.ListPicker, { ...props, title: this.state.title, setEnabled: this._setEnabled, items: this.state.items, iconSpec: "icon-saved-view", onExpanded: this._onExpanded, searchBox: this.state.searchBox, onSearchValueChange: (0, lodash_1.debounce)((search) => {
                this._searchInput = search;
                void this.loadViews();
            }, 300) }));
    }
}
exports.ViewSelector = ViewSelector;
ViewSelector._onViewSelectorShowUpdateEvent = new ViewSelectorShowUpdateEvent();
ViewSelector.defaultProps = {
    showSpatials: true,
    showDrawings: true,
    showSheets: true,
    showUnknown: true,
};
/** Gets the [[ViewSelectorChangedEvent]] */
ViewSelector.onViewSelectorChangedEvent = new ViewSelectorChangedEvent();
/** ViewSelector that is connected to the IModelConnection property in the Redux store. The application must set up the Redux store and include the FrameworkReducer.
 * @beta
 */
exports.IModelConnectedViewSelector = (0, connectIModel_1.connectIModelConnection)(null, null)(ViewSelector); // eslint-disable-line @typescript-eslint/naming-convention
//# sourceMappingURL=ViewSelector.js.map