"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 Frontstage
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.useItemsManager = exports.useFrontstageManager = exports.getFrontstageStateSettingName = exports.FRONTSTAGE_SETTINGS_NAMESPACE = exports.useSavedFrontstageState = exports.packNineZoneState = exports.restoreNineZoneState = exports.initializeNineZoneState = exports.stateVersion = exports.initializePanel = exports.isFrontstageStateSettingResult = exports.getPanelSectionWidgets = exports.getPanelSectionId = exports.addFrontstageWidgetDefs = exports.addPanelSectionWidgetDefs = exports.useLabels = exports.ActiveFrontstageDefProvider = exports.WidgetPanelsFrontstage = exports.useNineZoneDispatch = exports.useUpdateNineZoneSize = exports.useLayoutStore = void 0;
const components_react_1 = require("@itwin/components-react");
const core_bentley_1 = require("@itwin/core-bentley");
const core_frontend_1 = require("@itwin/core-frontend");
const core_react_1 = require("@itwin/core-react");
const immer_1 = require("immer");
const React = require("react");
const react_dom_1 = require("react-dom");
const FrontstageDef_1 = require("../frontstage/FrontstageDef");
const InternalFrontstageManager_1 = require("../frontstage/InternalFrontstageManager");
const useEscapeSetFocusToHome_1 = require("../hooks/useEscapeSetFocusToHome");
const useUiVisibility_1 = require("../hooks/useUiVisibility");
const LayoutStore_1 = require("../layout/base/LayoutStore");
const NineZone_1 = require("../layout/base/NineZone");
const activateDroppedTab_1 = require("../preview/activate-dropped-tab/activateDroppedTab");
const NineZoneState_1 = require("../layout/state/NineZoneState");
const NineZoneStateReducer_1 = require("../layout/state/NineZoneStateReducer");
const PanelState_1 = require("../layout/state/PanelState");
const FloatingWidgets_1 = require("../layout/widget/FloatingWidgets");
const PreviewHorizontalPanelAlign_1 = require("../preview/horizontal-panel-alignment/PreviewHorizontalPanelAlign");
const PreviewFeatures_1 = require("../preview/PreviewFeatures");
const StagePanelDef_1 = require("../stagepanels/StagePanelDef");
const StagePanelLocation_1 = require("../stagepanels/StagePanelLocation");
const StagePanelSection_1 = require("../stagepanels/StagePanelSection");
const StagePanelState_1 = require("../stagepanels/StagePanelState");
const UiItemsManager_1 = require("../ui-items-provider/UiItemsManager");
const UiFramework_1 = require("../UiFramework");
const useUiStateStorage_1 = require("../uistate/useUiStateStorage");
const WidgetState_1 = require("../widgets/WidgetState");
const Content_1 = require("./Content");
const FloatingWidget_1 = require("./FloatingWidget");
require("./Frontstage.scss");
const FrontstageContent_1 = require("./FrontstageContent");
const ModalFrontstageComposer_1 = require("./ModalFrontstageComposer");
const StatusBar_1 = require("./StatusBar");
const Tab_1 = require("./Tab");
const Toolbars_1 = require("./Toolbars");
const ToolSettings_1 = require("./ToolSettings");
const MaximizedWidget_1 = require("../preview/enable-maximized-widget/MaximizedWidget");
const StandardLayout_1 = require("../layout/StandardLayout");
const Panel_1 = require("../layout/widget-panels/Panel");
const ContentRenderer_1 = require("../layout/widget/ContentRenderer");
const CursorOverlay_1 = require("../layout/widget-panels/CursorOverlay");
const Expander_1 = require("../layout/widget-panels/Expander");
const useTranslation_1 = require("../hooks/useTranslation");
const PopoutWidgets_1 = require("../preview/reparent-popout-widgets/PopoutWidgets");
const useReduxFrameworkState_1 = require("../uistate/useReduxFrameworkState");
const ConfigurableUiContent_1 = require("../configurableui/ConfigurableUiContent");
const useSaveFrontstageSettings_1 = require("./useSaveFrontstageSettings");
const UiStateStorage_1 = require("../uistate/UiStateStorage");
function WidgetPanelsFrontstageComponent() {
    const activeModalFrontstageInfo = (0, ModalFrontstageComposer_1.useActiveModalFrontstageInfo)();
    const uiIsVisible = (0, useUiVisibility_1.useUiVisibility)();
    const previewFeatures = (0, PreviewFeatures_1.usePreviewFeatures)();
    (0, CursorOverlay_1.useCursor)();
    return (React.createElement(MaximizedWidget_1.MaximizedWidgetProvider, null,
        React.createElement(PreviewHorizontalPanelAlign_1.PreviewHorizontalPanelAlignFeatureProvider, { enabled: previewFeatures.horizontalPanelAlignment },
            React.createElement(components_react_1.ToolbarPopupAutoHideContext.Provider, { value: !uiIsVisible },
                React.createElement(ModalFrontstageComposer_1.ModalFrontstageComposer, { stageInfo: activeModalFrontstageInfo }),
                React.createElement(StandardLayout_1.StandardLayout, { centerContent: React.createElement(React.Fragment, null,
                        React.createElement(Toolbars_1.WidgetPanelsToolbars, null),
                        React.createElement(Expander_1.WidgetPanelExpanders, null)), toolSettings: React.createElement(ToolSettings_1.WidgetPanelsToolSettings, null), statusBar: React.createElement(StatusBar_1.WidgetPanelsStatusBar, null), topPanel: React.createElement(Panel_1.WidgetPanelProvider, { side: "top" }), leftPanel: React.createElement(Panel_1.WidgetPanelProvider, { side: "left" }), rightPanel: React.createElement(Panel_1.WidgetPanelProvider, { side: "right" }), bottomPanel: React.createElement(Panel_1.WidgetPanelProvider, { side: "bottom" }) },
                    React.createElement(FrontstageContent_1.WidgetPanelsFrontstageContent, null)),
                React.createElement(ContentRenderer_1.WidgetContentRenderers, null),
                React.createElement(FloatingWidgets_1.FloatingWidgets, null),
                React.createElement(PopoutWidgets_1.PopoutWidgets, null)))));
}
const widgetContent = React.createElement(Content_1.WidgetContent, null);
const toolSettingsContent = React.createElement(ToolSettings_1.ToolSettingsContent, null);
const widgetPanelsFrontstage = React.createElement(WidgetPanelsFrontstageComponent, null);
/** @internal */
function useLayoutStore(frontstageDef) {
    const layoutStore = React.useMemo(() => (0, LayoutStore_1.createLayoutStore)(frontstageDef?.nineZoneState), [frontstageDef]);
    React.useEffect(() => {
        return InternalFrontstageManager_1.InternalFrontstageManager.onFrontstageNineZoneStateChangedEvent.addListener((args) => {
            if (args.frontstageDef !== frontstageDef)
                return;
            (0, react_dom_1.unstable_batchedUpdates)(() => {
                // https://github.com/pmndrs/zustand/blob/main/docs/guides/event-handler-in-pre-react-18.md
                layoutStore.setState(args.state || defaultNineZone);
            });
        });
    }, [frontstageDef, layoutStore]);
    return layoutStore;
}
exports.useLayoutStore = useLayoutStore;
/** Update in-memory NineZoneState of newly activated frontstage with up to date size.
 * @internal
 */
function useUpdateNineZoneSize(frontstageDef) {
    React.useEffect(() => {
        const size = InternalFrontstageManager_1.InternalFrontstageManager.nineZoneSize;
        if (!size)
            return;
        frontstageDef.dispatch({
            type: "RESIZE",
            size: {
                height: size.height,
                width: size.width,
            },
        });
    }, [frontstageDef]);
}
exports.useUpdateNineZoneSize = useUpdateNineZoneSize;
const log = (reducer) => (state, action) => {
    core_bentley_1.Logger.logTrace("appui-react:reducer", `action ${action.type}`, () => ({
        action,
        state,
    }));
    return reducer(state, action);
};
/** @internal */
function useNineZoneDispatch(frontstageDef) {
    const features = (0, PreviewFeatures_1.usePreviewFeatures)();
    const reducer = React.useMemo(() => {
        let nineZoneStateReducer = log(NineZoneStateReducer_1.NineZoneStateReducer);
        nineZoneStateReducer = features.activateDroppedTab
            ? (0, activateDroppedTab_1.activateDroppedTab)(nineZoneStateReducer)
            : nineZoneStateReducer;
        return nineZoneStateReducer;
    }, [features.activateDroppedTab]);
    return React.useCallback((action) => {
        if (action.type === "RESIZE") {
            InternalFrontstageManager_1.InternalFrontstageManager.nineZoneSize = core_react_1.Size.create(action.size);
        }
        const state = frontstageDef.nineZoneState;
        if (!state)
            return;
        frontstageDef.nineZoneState = reducer(state, action);
    }, [frontstageDef, reducer]);
}
exports.useNineZoneDispatch = useNineZoneDispatch;
/** @internal */
function WidgetPanelsFrontstage() {
    const frontstageDef = (0, FrontstageDef_1.useActiveFrontstageDef)();
    React.useEffect(() => {
        const triggerWidowCloseProcessing = () => {
            frontstageDef && frontstageDef.setIsApplicationClosing(true);
        };
        window.addEventListener("unload", triggerWidowCloseProcessing);
        return () => {
            window.removeEventListener("unload", triggerWidowCloseProcessing);
        };
    }, [frontstageDef]);
    if (!frontstageDef)
        return null;
    return React.createElement(ActiveFrontstageDefProvider, { frontstageDef: frontstageDef });
}
exports.WidgetPanelsFrontstage = WidgetPanelsFrontstage;
const defaultNineZone = (0, NineZoneState_1.createNineZoneState)();
const tabElement = React.createElement(Tab_1.WidgetPanelsTab, null);
const floatingWidgetElement = React.createElement(FloatingWidget_1.FloatingWidget, null);
/** @internal */
function ActiveFrontstageDefProvider({ frontstageDef, }) {
    const configurableUi = React.useContext(ConfigurableUiContent_1.ConfigurableUiContext);
    const dispatch = useNineZoneDispatch(frontstageDef);
    frontstageDef.dispatch = dispatch;
    const layout = useLayoutStore(frontstageDef);
    useUpdateNineZoneSize(frontstageDef);
    useSavedFrontstageState(frontstageDef);
    (0, useSaveFrontstageSettings_1.useSaveFrontstageSettings)(frontstageDef, layout);
    useItemsManager(frontstageDef);
    const labels = useLabels();
    const uiIsVisible = (0, useUiVisibility_1.useUiVisibility)();
    const reduxToolAsToolSettingsLabel = (0, useReduxFrameworkState_1.useReduxFrameworkState)(
    // eslint-disable-next-line deprecation/deprecation
    (state) => state?.configurableUiState.useToolAsToolSettingsLabel);
    const reduxShowWidgetIcon = (0, useReduxFrameworkState_1.useReduxFrameworkState)(
    // eslint-disable-next-line deprecation/deprecation
    (state) => state?.configurableUiState.showWidgetIcon);
    const reduxAutoCollapseUnpinnedPanels = (0, useReduxFrameworkState_1.useReduxFrameworkState)(
    // eslint-disable-next-line deprecation/deprecation
    (state) => state?.configurableUiState.autoCollapseUnpinnedPanels);
    const reduxAnimateToolSettings = (0, useReduxFrameworkState_1.useReduxFrameworkState)(
    // eslint-disable-next-line deprecation/deprecation
    (state) => state?.configurableUiState.autoCollapseUnpinnedPanels);
    const showWidgetIcon = configurableUi.widgetIcon ?? reduxShowWidgetIcon ?? true;
    const autoCollapseUnpinnedPanels = configurableUi.collapsePanels ?? reduxAutoCollapseUnpinnedPanels ?? false;
    const animateToolSettings = configurableUi.animateToolSettings ?? reduxAnimateToolSettings ?? false;
    const useToolAsToolSettingsLabel = configurableUi.toolAsToolSettingsLabel ??
        reduxToolAsToolSettingsLabel ??
        false;
    useFrontstageManager(frontstageDef, useToolAsToolSettingsLabel);
    const handleKeyDown = (0, useEscapeSetFocusToHome_1.useEscapeSetFocusToHome)();
    return (React.createElement("div", { className: "uifw-widgetPanels-frontstage", onKeyDown: handleKeyDown, role: "presentation" },
        React.createElement(NineZone_1.NineZone, { dispatch: dispatch, labels: labels, layout: layout, tab: tabElement, floatingWidget: floatingWidgetElement, showWidgetIcon: showWidgetIcon, autoCollapseUnpinnedPanels: autoCollapseUnpinnedPanels, toolSettingsContent: toolSettingsContent, widgetContent: widgetContent, animateDockedToolSettings: animateToolSettings, uiIsVisible: uiIsVisible }, widgetPanelsFrontstage)));
}
exports.ActiveFrontstageDefProvider = ActiveFrontstageDefProvider;
/** @internal */
function useLabels() {
    const { translate } = (0, useTranslation_1.useTranslation)();
    return {
        dockToolSettingsTitle: translate("widget.tooltips.dockToolSettings"),
        moreWidgetsTitle: translate("widget.tooltips.moreWidgets"),
        moreToolSettingsTitle: translate("widget.tooltips.moreToolSettings"),
        pinPanelTitle: translate("widget.tooltips.pinPanel"),
        resizeGripTitle: translate("widget.tooltips.resizeGrip"),
        sendWidgetHomeTitle: translate("widget.tooltips.sendHome"),
        toolSettingsHandleTitle: translate("widget.tooltips.toolSettingsHandle"),
        unpinPanelTitle: translate("widget.tooltips.unpinPanel"),
        popoutActiveTab: translate("widget.tooltips.popoutActiveTab"),
    };
}
exports.useLabels = useLabels;
function toTabArgs(widget) {
    const label = getWidgetLabel(widget.label);
    const args = {
        allowedPanelTargets: widget.allowedPanelTargets?.map((location) => (0, StagePanelDef_1.toPanelSide)(location)),
        hideWithUiWhenFloating: !!widget.hideWithUiWhenFloating,
        canPopout: widget.canPopout,
        isFloatingWidgetResizable: widget.isFloatingStateWindowResizable,
        label,
        preferredFloatingWidgetSize: widget.defaultFloatingSize,
        preferredPanelWidgetSize: widget.preferredPanelSize,
    };
    return args;
}
function addWidgetDef(frontstageDef, widgetDef, location, section) {
    const side = (0, StagePanelDef_1.toPanelSide)(location);
    const isFloatingWidget = widgetDef.isFloatingStateSupported &&
        widgetDef.defaultState === WidgetState_1.WidgetState.Floating;
    const floatingWidgetId = widgetDef.floatingContainerId
        ? widgetDef.floatingContainerId
        : (0, NineZone_1.getUniqueId)();
    const userSized = !!widgetDef.defaultFloatingSize;
    frontstageDef.dispatch({
        type: "WIDGET_DEF_ADD",
        id: widgetDef.id,
        overrides: {
            ...toTabArgs(widgetDef),
            userSized,
        },
        location: isFloatingWidget ? "floating" : "panel",
        floatingWidget: {
            id: floatingWidgetId,
            preferredPosition: widgetDef.defaultFloatingPosition,
        },
        panelSection: {
            id: (0, PanelState_1.getWidgetPanelSectionId)(side, section),
            side,
            index: section,
        },
    });
    // Hide widget if `defaultState` is `Hidden` or `Unloaded`.
    hideWidgetDef(frontstageDef, widgetDef);
}
/** Adds missing widgets to the layout.
 * @internal
 */
function addPanelSectionWidgetDefs(frontstageDef, location, section) {
    const panelDef = frontstageDef.getStagePanelDef(location);
    if (!panelDef)
        return;
    const sectionDef = panelDef.getPanelSectionDef(section);
    const widgetDefs = determineNewWidgets(frontstageDef, sectionDef.widgetDefs);
    for (const widgetDef of widgetDefs) {
        addWidgetDef(frontstageDef, widgetDef, location, section);
    }
}
exports.addPanelSectionWidgetDefs = addPanelSectionWidgetDefs;
/** Sends back popout widgets if app is not an electron app. */
function processPopoutWidgets(frontstageDef) {
    if (core_bentley_1.ProcessDetector.isElectronAppFrontend)
        return;
    (0, core_bentley_1.assert)(!!frontstageDef.nineZoneState);
    const state = frontstageDef.nineZoneState;
    for (const id of state.popoutWidgets.allIds) {
        frontstageDef.dispatch({
            type: "POPOUT_WIDGET_SEND_BACK",
            id,
        });
    }
}
/** Opens popout widgets if app is an electron app. */
function openPopoutWidgets(frontstageDef) {
    // Only electron can reopen popout windows w/o user interaction.
    if (!core_bentley_1.ProcessDetector.isElectronAppFrontend)
        return;
    (0, core_bentley_1.assert)(!!frontstageDef.nineZoneState);
    const state = frontstageDef.nineZoneState;
    for (const id of state.popoutWidgets.allIds) {
        frontstageDef.openPopoutWidgetContainer(id, undefined);
    }
}
/** Adds frontstageDef widgets that are missing in NineZoneState.
 * @internal
 */
function addFrontstageWidgetDefs(frontstageDef) {
    [
        StagePanelLocation_1.StagePanelLocation.Left,
        StagePanelLocation_1.StagePanelLocation.Right,
        StagePanelLocation_1.StagePanelLocation.Top,
        StagePanelLocation_1.StagePanelLocation.Bottom,
    ].forEach((location) => [StagePanelSection_1.StagePanelSection.Start, StagePanelSection_1.StagePanelSection.End].forEach((section) => addPanelSectionWidgetDefs(frontstageDef, location, section)));
    const toolSettingsWidgetDefs = determineNewWidgets(frontstageDef, frontstageDef.toolSettings ? [frontstageDef.toolSettings] : undefined);
    for (const toolSettingsWidgetDef of toolSettingsWidgetDefs) {
        frontstageDef.dispatch({
            type: "WIDGET_DEF_ADD_TOOL_SETTINGS",
            id: toolSettingsWidgetDef.id,
            overrides: toTabArgs(toolSettingsWidgetDef),
        });
    }
}
exports.addFrontstageWidgetDefs = addFrontstageWidgetDefs;
/** Hide widgets with `Hidden` or `Unloaded` defaultState. */
function hideWidgetDefs(frontstageDef) {
    (0, core_bentley_1.assert)(!!frontstageDef.nineZoneState);
    const state = frontstageDef.nineZoneState;
    const tabs = Object.values(state.tabs);
    for (const tab of tabs) {
        const widgetDef = frontstageDef.findWidgetDef(tab.id);
        if (!widgetDef)
            continue;
        hideWidgetDef(frontstageDef, widgetDef);
    }
}
/** Hide widget with `Hidden` or `Unloaded` defaultState. */
function hideWidgetDef(frontstageDef, widgetDef) {
    if (widgetDef.defaultState === WidgetState_1.WidgetState.Hidden) {
        frontstageDef.dispatch({
            type: "WIDGET_TAB_HIDE",
            id: widgetDef.id,
        });
    }
    if (widgetDef.defaultState === WidgetState_1.WidgetState.Unloaded) {
        frontstageDef.dispatch({
            type: "WIDGET_TAB_UNLOAD",
            id: widgetDef.id,
        });
    }
}
/** Removes NineZoneState widgets that are missing in frontstageDef.
 * @internal
 */
function removeMissingWidgets(frontstageDef) {
    const state = frontstageDef.nineZoneState;
    if (!state)
        return;
    const toolSettingsTabId = state.toolSettings?.tabId;
    for (const [, tab] of Object.entries(state.tabs)) {
        if (tab.id === toolSettingsTabId)
            continue;
        const widgetDef = frontstageDef.findWidgetDef(tab.id);
        if (widgetDef)
            continue;
        frontstageDef.dispatch({
            type: "WIDGET_TAB_REMOVE",
            id: tab.id,
        });
    }
}
function getWidgetLabel(label) {
    return label === "" ? "Widget" : label;
}
/** @internal */
function getPanelSectionId(location, section) {
    return `${StagePanelLocation_1.StagePanelLocation[location].toLowerCase()}${StagePanelSection_1.StagePanelSection[section]}`;
}
exports.getPanelSectionId = getPanelSectionId;
/** @internal */
function getPanelSectionWidgets(frontstageDef, location, section) {
    const stagePanel = frontstageDef.getStagePanelDef(location);
    const panelSection = stagePanel?.getPanelSectionDef(section);
    return panelSection?.widgetDefs || [];
}
exports.getPanelSectionWidgets = getPanelSectionWidgets;
/** @internal */
function isFrontstageStateSettingResult(settingsResult) {
    if (settingsResult.status === UiStateStorage_1.UiStateStorageStatus.Success)
        return true;
    return false;
}
exports.isFrontstageStateSettingResult = isFrontstageStateSettingResult;
/** @internal */
function initializePanel(frontstageDef, location) {
    const side = (0, StagePanelDef_1.toPanelSide)(location);
    const panelDef = frontstageDef.getStagePanelDef(location);
    if (!panelDef)
        return;
    // eslint-disable-next-line deprecation/deprecation
    const size = panelDef.initialConfig?.sizeSpec ?? panelDef.initialConfig?.size;
    size !== undefined &&
        frontstageDef.dispatch({
            type: "PANEL_SET_SIZE",
            side,
            size,
        });
    frontstageDef.dispatch({
        type: "PANEL_SET_PINNED",
        side,
        pinned: panelDef.defaultPinned,
    });
    frontstageDef.dispatch({
        type: "PANEL_SET_RESIZABLE",
        side,
        resizable: panelDef.defaultResizable,
    });
    const minSize = panelDef.initialConfig?.minSizeSpec ?? panelDef.initialConfig?.minSize; // eslint-disable-line deprecation/deprecation
    minSize !== undefined &&
        frontstageDef.dispatch({
            type: "PANEL_SET_MIN_SIZE",
            side,
            minSize,
        });
    const maxSize = panelDef.initialConfig?.maxSizeSpec ?? panelDef.initialConfig?.maxSize; // eslint-disable-line deprecation/deprecation
    maxSize !== undefined &&
        frontstageDef.dispatch({
            type: "PANEL_SET_MAX_SIZE",
            side,
            maxSize,
        });
    const collapsed = panelDef.defaultState !== StagePanelState_1.StagePanelState.Open;
    frontstageDef.dispatch({
        type: "PANEL_SET_COLLAPSED",
        side,
        collapsed,
    });
}
exports.initializePanel = initializePanel;
/** @internal */
exports.stateVersion = 18; // this needs to be bumped when NineZoneState is changed (to recreate the layout).
/** @internal */
function initializeNineZoneState(frontstageDef) {
    frontstageDef.batch(() => {
        frontstageDef.nineZoneState = defaultNineZone;
        const size = InternalFrontstageManager_1.InternalFrontstageManager.nineZoneSize;
        size &&
            frontstageDef.dispatch({
                type: "RESIZE",
                size,
            });
        addFrontstageWidgetDefs(frontstageDef);
        initializePanel(frontstageDef, StagePanelLocation_1.StagePanelLocation.Left);
        initializePanel(frontstageDef, StagePanelLocation_1.StagePanelLocation.Right);
        initializePanel(frontstageDef, StagePanelLocation_1.StagePanelLocation.Top);
        initializePanel(frontstageDef, StagePanelLocation_1.StagePanelLocation.Bottom);
    });
}
exports.initializeNineZoneState = initializeNineZoneState;
/** Converts from saved NineZoneState to NineZoneState.
 * @note Restores toolSettings tab.
 * @note Restores tab labels.
 * @internal
 */
function restoreNineZoneState(frontstageDef, packed) {
    frontstageDef.batch(() => {
        frontstageDef.nineZoneState = packed;
        for (const [, tab] of Object.entries(packed.tabs)) {
            const widgetDef = frontstageDef.findWidgetDef(tab.id);
            if (!widgetDef) {
                core_bentley_1.Logger.logInfo(UiFramework_1.UiFramework.loggerCategory(restoreNineZoneState), "WidgetDef is not found for saved tab.", {
                    frontstageId: frontstageDef.id,
                    tabId: tab.id,
                });
                frontstageDef.dispatch({ type: "WIDGET_TAB_REMOVE", id: tab.id });
                continue;
            }
            frontstageDef.dispatch({
                type: "WIDGET_TAB_UPDATE",
                id: tab.id,
                overrides: toTabArgs(widgetDef),
            });
        }
        frontstageDef.nineZoneState = (0, immer_1.default)(frontstageDef.nineZoneState, (draft) => {
            // remove center panel section if one is found in left or right panels
            const oldLeftMiddleIndex = packed.panels.left.widgets.findIndex((value) => value === "leftMiddle");
            if (-1 !== oldLeftMiddleIndex) {
                draft.panels.left.widgets = packed.panels.left.widgets.filter((value) => value !== "leftMiddle");
                if ("leftEnd" in draft.widgets) {
                    draft.widgets.leftMiddle.tabs.forEach((tab) => draft.widgets.leftEnd.tabs.push(tab));
                }
                else {
                    draft.widgets.leftEnd = { ...draft.widgets.leftMiddle };
                    delete draft.widgets.leftMiddle;
                }
            }
            const oldRightMiddleIndex = packed.panels.right.widgets.findIndex((value) => value === "rightMiddle");
            if (-1 !== oldRightMiddleIndex) {
                draft.panels.right.widgets = packed.panels.right.widgets.filter((value) => value !== "rightMiddle");
                if ("rightEnd" in draft.widgets) {
                    draft.widgets.rightMiddle.tabs.forEach((tab) => draft.widgets.rightEnd.tabs.push(tab));
                }
                else {
                    draft.widgets.rightEnd = { ...draft.widgets.rightMiddle };
                    delete draft.widgets.rightMiddle;
                }
            }
            return;
        });
        if (InternalFrontstageManager_1.InternalFrontstageManager.nineZoneSize &&
            (0 !== InternalFrontstageManager_1.InternalFrontstageManager.nineZoneSize.height ||
                0 !== InternalFrontstageManager_1.InternalFrontstageManager.nineZoneSize.width)) {
            frontstageDef.dispatch({
                type: "RESIZE",
                size: {
                    height: InternalFrontstageManager_1.InternalFrontstageManager.nineZoneSize.height,
                    width: InternalFrontstageManager_1.InternalFrontstageManager.nineZoneSize.width,
                },
            });
        }
        addFrontstageWidgetDefs(frontstageDef);
        hideWidgetDefs(frontstageDef);
        processPopoutWidgets(frontstageDef);
    });
}
exports.restoreNineZoneState = restoreNineZoneState;
/** Prepares NineZoneState to be saved.
 * @note Removes toolSettings tab.
 * @note Removes tab labels and iconSpec.
 * @internal
 */
function packNineZoneState(state) {
    let packed = state;
    packed = (0, immer_1.default)(packed, (draft) => {
        for (const [, tab] of Object.entries(draft.tabs)) {
            tab.label = "";
        }
    });
    return packed;
}
exports.packNineZoneState = packNineZoneState;
/** @internal */
function useSavedFrontstageState(frontstageDef) {
    const uiStateStorage = (0, useUiStateStorage_1.useUiStateStorageHandler)();
    const uiStateStorageRef = React.useRef(uiStateStorage);
    const isMountedRef = React.useRef(false);
    React.useEffect(() => {
        isMountedRef.current = true;
        return () => {
            isMountedRef.current = false;
        };
    }, []);
    React.useEffect(() => {
        uiStateStorageRef.current = uiStateStorage;
    }, [uiStateStorage]);
    React.useEffect(() => {
        async function fetchFrontstageState() {
            // Switching to previously initialized frontstage.
            if (frontstageDef.nineZoneState) {
                processPopoutWidgets(frontstageDef);
                openPopoutWidgets(frontstageDef);
                return;
            }
            const id = frontstageDef.id;
            const version = frontstageDef.version;
            const settingResult = await uiStateStorageRef.current.getSetting(exports.FRONTSTAGE_SETTINGS_NAMESPACE, getFrontstageStateSettingName(id));
            if (!isMountedRef.current)
                return;
            if (isFrontstageStateSettingResult(settingResult)) {
                const setting = settingResult.setting;
                if (setting.version === version &&
                    setting.stateVersion === exports.stateVersion) {
                    restoreNineZoneState(frontstageDef, setting.nineZone);
                    return;
                }
            }
            initializeNineZoneState(frontstageDef);
        }
        void fetchFrontstageState();
    }, [frontstageDef]);
}
exports.useSavedFrontstageState = useSavedFrontstageState;
/** @internal */
exports.FRONTSTAGE_SETTINGS_NAMESPACE = "uifw-frontstageSettings";
/** @internal */
function getFrontstageStateSettingName(frontstageId) {
    return `frontstageState[${frontstageId}]`;
}
exports.getFrontstageStateSettingName = getFrontstageStateSettingName;
/** @internal */
function useFrontstageManager(frontstageDef, useToolAsToolSettingsLabel) {
    const { translate } = (0, useTranslation_1.useTranslation)();
    const uiSettingsStorage = (0, useUiStateStorage_1.useUiStateStorageHandler)();
    React.useEffect(() => {
        return InternalFrontstageManager_1.InternalFrontstageManager.onFrontstageRestoreLayoutEvent.addListener((args) => {
            // TODO: track restoring frontstages to support workflows:  i.e. prevent loading frontstage OR saving layout when delete is pending
            void uiSettingsStorage.deleteSetting(exports.FRONTSTAGE_SETTINGS_NAMESPACE, getFrontstageStateSettingName(args.frontstageDef.id));
            if (frontstageDef.id === args.frontstageDef.id) {
                initializeNineZoneState(frontstageDef);
                return;
            }
            args.frontstageDef.nineZoneState = undefined;
        });
    }, [uiSettingsStorage, frontstageDef]);
    const defaultLabel = translate("widget.labels.toolSettings");
    React.useEffect(() => {
        const updateLabel = () => {
            const state = frontstageDef.nineZoneState;
            if (!state)
                return;
            const toolSettingsTabId = state.toolSettings?.tabId;
            if (!toolSettingsTabId)
                return;
            const toolId = UiFramework_1.UiFramework.frontstages.activeToolId;
            const label = useToolAsToolSettingsLabel
                ? core_frontend_1.IModelApp.tools.find(toolId)?.flyover || defaultLabel
                : defaultLabel;
            frontstageDef.dispatch({
                type: "WIDGET_TAB_SET_LABEL",
                id: toolSettingsTabId,
                label,
            });
        };
        // Whenever the frontstageDef or the useTool... changes, keep the label up to date.
        updateLabel();
        const removeListenerFuncs = [];
        // If useTool... is true, listen for events to keep up the label up to date.
        if (useToolAsToolSettingsLabel) {
            removeListenerFuncs.push(UiFramework_1.UiFramework.frontstages.onFrontstageReadyEvent.addListener(updateLabel), InternalFrontstageManager_1.InternalFrontstageManager.onFrontstageRestoreLayoutEvent.addListener(updateLabel), UiFramework_1.UiFramework.frontstages.onToolActivatedEvent.addListener(updateLabel), UiFramework_1.UiFramework.frontstages.onToolSettingsReloadEvent.addListener(updateLabel));
        }
        return () => {
            removeListenerFuncs.forEach((removeListener) => removeListener());
        };
    }, [frontstageDef, useToolAsToolSettingsLabel, defaultLabel]);
}
exports.useFrontstageManager = useFrontstageManager;
function refreshNineZoneState(frontstageDef) {
    // Fired for both registered/unregistered. Update definitions and remove/add missing widgets.
    frontstageDef.updateWidgetDefs();
    frontstageDef.batch(() => {
        addFrontstageWidgetDefs(frontstageDef);
        removeMissingWidgets(frontstageDef);
    });
}
/** @internal */
function useItemsManager(frontstageDef) {
    React.useEffect(() => {
        // Not initialized yet.
        if (!frontstageDef.nineZoneState)
            return;
        // Need to refresh because UiItemsProvider may have added something while another frontstage was active.
        refreshNineZoneState(frontstageDef);
    }, [frontstageDef]);
    React.useEffect(() => {
        return UiItemsManager_1.UiItemsManager.onUiProviderRegisteredEvent.addListener(() => {
            refreshNineZoneState(frontstageDef);
        });
    }, [frontstageDef]);
}
exports.useItemsManager = useItemsManager;
function determineNewWidgets(frontstageDef, defs) {
    const state = frontstageDef.nineZoneState;
    (0, core_bentley_1.assert)(!!state);
    defs = defs || [];
    const uniqueDefs = defs.filter((def, index, array) => {
        return index === array.findIndex((def1) => def.id === def1.id);
    });
    return uniqueDefs.filter((def) => !(def.id in state.tabs));
}
//# sourceMappingURL=Frontstage.js.map