"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 Base
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.NineZoneStateReducer = void 0;
const immer_1 = require("immer");
const core_react_1 = require("@itwin/core-react");
const core_bentley_1 = require("@itwin/core-bentley");
const WidgetLocation_1 = require("./WidgetLocation");
const DropTargetState_1 = require("./DropTargetState");
const PanelState_1 = require("./PanelState");
const PanelStateHelpers_1 = require("./internal/PanelStateHelpers");
const TabStateHelpers_1 = require("./internal/TabStateHelpers");
const NineZoneStateHelpers_1 = require("./internal/NineZoneStateHelpers");
const WidgetStateHelpers_1 = require("./internal/WidgetStateHelpers");
const SendBack_1 = require("../widget/SendBack");
const Panel_1 = require("../widget-panels/Panel");
const TabLocation_1 = require("./TabLocation");
const NineZone_1 = require("../base/NineZone");
const WidgetRestoreState_1 = require("./WidgetRestoreState");
const ToolSettingsStateHelpers_1 = require("./internal/ToolSettingsStateHelpers");
/** @internal */
function NineZoneStateReducer(state, action) {
    switch (action.type) {
        case "RESIZE": {
            state = (0, immer_1.produce)(state, (draft) => {
                (0, NineZoneStateHelpers_1.setSizeProps)(draft.size, action.size);
            });
            const nzBounds = core_react_1.Rectangle.createFromSize(action.size);
            for (const id of state.floatingWidgets.allIds) {
                const floatingWidget = state.floatingWidgets.byId[id];
                const bounds = core_react_1.Rectangle.create(floatingWidget.bounds);
                const containedBounds = bounds.containIn(nzBounds);
                state = (0, WidgetStateHelpers_1.updateFloatingWidgetState)(state, id, {
                    bounds: containedBounds.toProps(),
                });
            }
            for (const side of Panel_1.panelSides) {
                state = (0, PanelStateHelpers_1.updatePanelState)(state, side, (draft) => {
                    const size = (0, PanelStateHelpers_1.getPanelSize)(draft.size, side, draft.minSize, draft.maxSize, state.size);
                    draft.size = size;
                });
            }
            return state;
        }
        case "PANEL_TOGGLE_COLLAPSED": {
            return (0, PanelStateHelpers_1.updatePanelState)(state, action.side, (draft) => {
                draft.collapsed = !draft.collapsed;
            });
        }
        case "PANEL_SET_COLLAPSED": {
            return (0, PanelStateHelpers_1.updatePanelState)(state, action.side, (draft) => {
                draft.collapsed = action.collapsed;
            });
        }
        case "PANEL_SET_SIZE": {
            const { side, size: preferredSize } = action;
            return (0, PanelStateHelpers_1.updatePanelState)(state, side, (draft) => {
                const size = (0, PanelStateHelpers_1.getPanelSize)(preferredSize, draft.side, draft.minSize, draft.maxSize, state.size);
                draft.size = size;
            });
        }
        case "PANEL_SET_MIN_SIZE": {
            return (0, PanelStateHelpers_1.updatePanelState)(state, action.side, (draft) => {
                const size = (0, PanelStateHelpers_1.getPanelSize)(draft.size, draft.side, action.minSize, draft.maxSize, state.size);
                const minSizeInPixels = (0, PanelStateHelpers_1.getPanelPixelSizeFromSpec)(draft.side, state.size, action.minSize);
                draft.minSize = minSizeInPixels;
                draft.size = size;
            });
        }
        case "PANEL_SET_MAX_SIZE": {
            return (0, PanelStateHelpers_1.updatePanelState)(state, action.side, (draft) => {
                const size = (0, PanelStateHelpers_1.getPanelSize)(draft.size, draft.side, draft.minSize, action.maxSize, state.size);
                draft.maxSize = action.maxSize;
                draft.size = size;
            });
        }
        case "PANEL_SET_RESIZABLE": {
            return (0, PanelStateHelpers_1.updatePanelState)(state, action.side, (draft) => {
                draft.resizable = action.resizable;
            });
        }
        case "PANEL_SET_SPLITTER_VALUE": {
            const splitterPercent = Math.min(Math.max(action.percent, 0), 100);
            return (0, PanelStateHelpers_1.updatePanelState)(state, action.side, (draft) => {
                draft.splitterPercent = splitterPercent;
            });
        }
        case "PANEL_TOGGLE_SPAN": {
            const { side } = action;
            return (0, PanelStateHelpers_1.updatePanelState)(state, side, (draft) => {
                draft.span = !draft.span;
            });
        }
        case "PANEL_SET_PINNED": {
            return (0, PanelStateHelpers_1.updatePanelState)(state, action.side, (draft) => {
                draft.pinned = action.pinned;
            });
        }
        case "PANEL_TOGGLE_PINNED": {
            return (0, PanelStateHelpers_1.updatePanelState)(state, action.side, (draft) => {
                draft.pinned = !draft.pinned;
            });
        }
        case "PANEL_INITIALIZE": {
            return (0, PanelStateHelpers_1.updatePanelState)(state, action.side, (draft) => {
                const size = (0, PanelStateHelpers_1.getPanelSize)(action.size, draft.side, draft.minSize, draft.maxSize, state.size);
                draft.size = size;
            });
        }
        case "PANEL_WIDGET_DRAG_START": {
            const { side, newFloatingWidgetId } = action;
            const panel = state.panels[side];
            const widgetIndex = panel.widgets.indexOf(action.id);
            const widget = (0, WidgetStateHelpers_1.getWidgetState)(state, action.id);
            state = (0, WidgetStateHelpers_1.removePanelWidget)(state, action.id);
            return (0, WidgetStateHelpers_1.addFloatingWidget)(state, newFloatingWidgetId, widget.tabs, {
                bounds: core_react_1.Rectangle.create(action.bounds).toProps(),
                userSized: action.userSized,
                id: action.newFloatingWidgetId,
                home: {
                    side: action.side,
                    widgetId: "",
                    widgetIndex,
                },
            }, {
                ...widget,
                minimized: false,
            });
        }
        case "WIDGET_DRAG": {
            const { floatingWidgetId, dragBy } = action;
            const floatingWidget = state.floatingWidgets.byId[floatingWidgetId];
            const newBounds = core_react_1.Rectangle.create(floatingWidget.bounds).offset(dragBy);
            return (0, WidgetStateHelpers_1.updateFloatingWidgetState)(state, floatingWidgetId, {
                bounds: newBounds.toProps(),
            });
        }
        case "WIDGET_DRAG_END": {
            // TODO: handle duplicates in WIDGET_TAB_DRAG_END action
            const { target, floatingWidgetId } = action;
            const floatingWidget = state.floatingWidgets.byId[floatingWidgetId];
            const draggedWidget = (0, WidgetStateHelpers_1.getWidgetState)(state, floatingWidgetId);
            if ((0, DropTargetState_1.isWindowDropTargetState)(target)) {
                const nzBounds = core_react_1.Rectangle.createFromSize(state.size);
                let newBounds = core_react_1.Rectangle.create(floatingWidget.bounds);
                if (draggedWidget.minimized) {
                    const containedBounds = newBounds.setHeight(35).containIn(nzBounds);
                    newBounds = newBounds.setPosition(containedBounds.topLeft());
                }
                else {
                    newBounds = newBounds.containIn(nzBounds);
                }
                state = (0, WidgetStateHelpers_1.updateFloatingWidgetState)(state, floatingWidgetId, {
                    bounds: newBounds.toProps(),
                });
                return (0, WidgetStateHelpers_1.floatingWidgetBringToFront)(state, floatingWidgetId);
            }
            state = (0, WidgetStateHelpers_1.removeFloatingWidget)(state, floatingWidgetId);
            if ((0, DropTargetState_1.isTabDropTargetState)(target)) {
                state = (0, NineZoneStateHelpers_1.updateHomeOfToolSettingsWidget)(state, target.widgetId, floatingWidget.home);
                const targetWidget = (0, WidgetStateHelpers_1.getWidgetState)(state, target.widgetId);
                const tabs = [...targetWidget.tabs];
                tabs.splice(target.tabIndex, 0, ...draggedWidget.tabs);
                state = (0, WidgetStateHelpers_1.updateWidgetState)(state, target.widgetId, {
                    tabs,
                });
            }
            else if ((0, DropTargetState_1.isSectionDropTargetState)(target)) {
                state = (0, PanelStateHelpers_1.updatePanelState)(state, target.side, (draft) => {
                    draft.widgets.splice(target.sectionIndex, 0, target.newWidgetId);
                    draft.collapsed = false;
                });
                state = (0, WidgetStateHelpers_1.addWidgetState)(state, target.newWidgetId, draggedWidget.tabs, draggedWidget);
            }
            else if ((0, DropTargetState_1.isWidgetDropTargetState)(target)) {
                state = (0, NineZoneStateHelpers_1.updateHomeOfToolSettingsWidget)(state, target.widgetId, floatingWidget.home);
                const widget = (0, WidgetLocation_1.getWidgetLocation)(state, target.widgetId);
                if (widget && (0, WidgetLocation_1.isPanelWidgetLocation)(widget)) {
                    state = (0, PanelStateHelpers_1.updatePanelState)(state, widget.side, (draft) => {
                        draft.collapsed = false;
                    });
                }
                const targetWidget = (0, WidgetStateHelpers_1.getWidgetState)(state, target.widgetId);
                const tabs = [...targetWidget.tabs];
                tabs.splice(targetWidget.tabs.length, 0, ...draggedWidget.tabs);
                state = (0, WidgetStateHelpers_1.updateWidgetState)(state, target.widgetId, {
                    tabs,
                });
            }
            else {
                const panelSectionId = (0, PanelState_1.getWidgetPanelSectionId)(target.side, 0);
                state = (0, PanelStateHelpers_1.updatePanelState)(state, target.side, (draft) => {
                    draft.widgets = [panelSectionId];
                    draft.collapsed = false;
                });
                state = (0, WidgetStateHelpers_1.addWidgetState)(state, panelSectionId, draggedWidget.tabs, {
                    ...draggedWidget,
                    minimized: false,
                });
            }
            return state;
        }
        case "FLOATING_WIDGET_RESIZE": {
            const { resizeBy } = action;
            const widget = (0, WidgetStateHelpers_1.getWidgetState)(state, action.id);
            const floatingWidget = state.floatingWidgets.byId[action.id];
            // if this is not a tool settings widget then set the userSized flag
            if (!(0, NineZoneStateHelpers_1.isToolSettingsFloatingWidget)(state, action.id)) {
                state = (0, WidgetStateHelpers_1.updateFloatingWidgetState)(state, action.id, {
                    userSized: true,
                });
            }
            const minWidth = 200;
            const minHeight = 120;
            let newBounds = core_react_1.Rectangle.create(floatingWidget.bounds);
            // Resize top-left corner.
            const maxLeft = newBounds.right - minWidth;
            const maxTop = newBounds.bottom - minHeight;
            newBounds = newBounds.inset(-resizeBy.left, -resizeBy.top, 0, 0);
            const left = Math.min(maxLeft, newBounds.left);
            const top = Math.min(maxTop, newBounds.top);
            newBounds = new core_react_1.Rectangle(left, top, newBounds.right, newBounds.bottom);
            // Resize bottom-right corner.
            const minRight = newBounds.left + minWidth;
            const minBottom = newBounds.top + minHeight;
            newBounds = newBounds.inset(0, 0, -resizeBy.right, -resizeBy.bottom);
            const right = Math.max(minRight, newBounds.right);
            const bottom = Math.max(minBottom, newBounds.bottom);
            newBounds = new core_react_1.Rectangle(left, top, right, bottom);
            state = (0, WidgetStateHelpers_1.updateFloatingWidgetState)(state, action.id, {
                bounds: newBounds,
            });
            const tab = state.tabs[widget.activeTabId];
            if (tab.isFloatingWidgetResizable) {
                const size = newBounds.getSize();
                state = (0, TabStateHelpers_1.updateTabState)(state, widget.activeTabId, (draft) => {
                    (0, NineZoneStateHelpers_1.initSizeProps)(draft, "preferredFloatingWidgetSize", size);
                    draft.userSized = true;
                });
            }
            return state;
        }
        case "FLOATING_WIDGET_SET_BOUNDS": {
            const nzBounds = core_react_1.Rectangle.createFromSize(state.size);
            const bounds = core_react_1.Rectangle.create(action.bounds).containIn(nzBounds);
            return (0, WidgetStateHelpers_1.updateFloatingWidgetState)(state, action.id, {
                bounds: bounds.toProps(),
            });
        }
        case "FLOATING_WIDGET_CLEAR_USER_SIZED": {
            return (0, immer_1.produce)(state, (draft) => {
                const floatingWidget = draft.floatingWidgets.byId[action.id];
                floatingWidget.userSized = false;
                const widget = (0, WidgetStateHelpers_1.getWidgetState)(draft, action.id);
                const tab = draft.tabs[widget.activeTabId];
                tab.userSized = false;
            });
        }
        case "FLOATING_WIDGET_SET_USER_SIZED": {
            return (0, immer_1.produce)(state, (draft) => {
                const floatingWidget = draft.floatingWidgets.byId[action.id];
                floatingWidget.userSized = action.userSized;
            });
        }
        case "FLOATING_WIDGET_BRING_TO_FRONT": {
            return (0, WidgetStateHelpers_1.floatingWidgetBringToFront)(state, action.id);
        }
        case "FLOATING_WIDGET_SEND_BACK": {
            const widget = (0, WidgetStateHelpers_1.getWidgetState)(state, action.id);
            const sendBackHomeState = (0, SendBack_1.getSendBackHomeState)(state, action.id);
            // Add tabs to an existing widget.
            if (sendBackHomeState.widgetId) {
                const destinationWidget = state.widgets[sendBackHomeState.widgetId];
                const tabs = [...destinationWidget.tabs, ...widget.tabs];
                state = (0, WidgetStateHelpers_1.updateWidgetState)(state, destinationWidget.id, {
                    tabs,
                });
                return (0, WidgetStateHelpers_1.removeWidget)(state, widget.id);
            }
            const sectionIndex = sendBackHomeState.sectionIndex ?? 0;
            const home = state.floatingWidgets.byId[action.id].home;
            const destinationWidgetId = home.widgetId
                ? home.widgetId
                : (0, PanelState_1.getWidgetPanelSectionId)(home.side, sectionIndex);
            // Add tabs to a new panel widget.
            state = (0, WidgetStateHelpers_1.removeWidget)(state, widget.id);
            return (0, PanelStateHelpers_1.insertPanelWidget)(state, sendBackHomeState.side, destinationWidgetId, widget.tabs, sectionIndex);
        }
        case "POPOUT_WIDGET_SEND_BACK": {
            const popoutWidget = state.popoutWidgets.byId[action.id];
            const widget = (0, WidgetStateHelpers_1.getWidgetState)(state, action.id);
            const home = popoutWidget.home;
            state = (0, WidgetStateHelpers_1.removeWidget)(state, widget.id);
            // Determine existing widget.
            let existingWidget;
            if (home.widgetId in state.widgets) {
                existingWidget = state.widgets[home.widgetId];
            }
            else if ((0, WidgetRestoreState_1.isPanelWidgetRestoreState)(home)) {
                const panel = state.panels[home.side];
                const panelSectionId = (0, PanelState_1.getWidgetPanelSectionId)(home.side, home.widgetIndex);
                existingWidget = state.widgets[panelSectionId];
                // Can not add additional sections, add to an existing one.
                if (!existingWidget && panel.widgets.length >= panel.maxWidgetCount) {
                    const sectionIndex = Math.min(panel.maxWidgetCount - 1, home.widgetIndex);
                    const sectionId = panel.widgets[sectionIndex];
                    existingWidget = state.widgets[sectionId];
                }
            }
            // Add to an existing widget.
            if (existingWidget) {
                const tabs = [...existingWidget.tabs, ...widget.tabs];
                return (0, WidgetStateHelpers_1.updateWidgetState)(state, existingWidget.id, {
                    tabs,
                });
            }
            // Insert a new panel section.
            if ((0, WidgetRestoreState_1.isPanelWidgetRestoreState)(home)) {
                const sectionId = home.widgetId
                    ? home.widgetId
                    : (0, PanelState_1.getWidgetPanelSectionId)(home.side, home.widgetIndex);
                return (0, PanelStateHelpers_1.insertPanelWidget)(state, home.side, sectionId, [...widget.tabs], home.widgetIndex);
            }
            // Add a new floating widget.
            return (0, WidgetStateHelpers_1.addFloatingWidget)(state, home.widgetId, widget.tabs, home.floatingWidget);
        }
        case "WIDGET_TAB_ADD_TO_WIDGET": {
            const { id, widgetId } = action;
            return (0, TabStateHelpers_1.addTabToWidget)(state, id, widgetId);
        }
        case "WIDGET_TAB_CLICK": {
            const { id, widgetId } = action;
            state = (0, WidgetStateHelpers_1.setWidgetActiveTabId)(state, widgetId, id);
            return (0, WidgetStateHelpers_1.updateWidgetState)(state, widgetId, {
                minimized: false,
            });
        }
        case "WIDGET_TAB_DOUBLE_CLICK": {
            if (action.floatingWidgetId === undefined)
                return state;
            const widget = (0, WidgetStateHelpers_1.getWidgetState)(state, action.widgetId);
            const active = action.id === widget.activeTabId;
            if (!active)
                return (0, WidgetStateHelpers_1.setWidgetActiveTabId)(state, widget.id, action.id);
            return (0, WidgetStateHelpers_1.updateWidgetState)(state, widget.id, {
                minimized: !widget.minimized,
            });
        }
        case "WIDGET_TAB_DRAG_START": {
            const tabId = action.id;
            let home;
            if (action.floatingWidgetId) {
                const floatingWidget = state.floatingWidgets.byId[action.floatingWidgetId];
                home = floatingWidget.home;
            }
            else {
                (0, core_bentley_1.assert)(!!action.side);
                const panel = state.panels[action.side];
                const widgetIndex = panel.widgets.indexOf(action.widgetId);
                home = {
                    side: action.side,
                    widgetId: action.widgetId,
                    widgetIndex,
                };
            }
            state = (0, immer_1.produce)(state, (draft) => {
                draft.draggedTab = (0, TabStateHelpers_1.createDraggedTabState)(tabId, {
                    position: core_react_1.Point.create(action.position).toProps(),
                    home,
                });
            });
            return (0, TabStateHelpers_1.removeTabFromWidget)(state, tabId);
        }
        case "WIDGET_TAB_DRAG": {
            return (0, immer_1.produce)(state, (draft) => {
                const draggedTab = draft.draggedTab;
                (0, core_bentley_1.assert)(!!draggedTab);
                const position = core_react_1.Point.create(draggedTab.position).offset(action.dragBy);
                (0, NineZoneStateHelpers_1.setPointProps)(draggedTab.position, position);
            });
        }
        case "WIDGET_TAB_DRAG_END": {
            (0, core_bentley_1.assert)(!!state.draggedTab);
            const target = action.target;
            if ((0, DropTargetState_1.isTabDropTargetState)(target)) {
                state = (0, NineZoneStateHelpers_1.updateHomeOfToolSettingsWidget)(state, target.widgetId, state.draggedTab.home);
                const targetWidget = (0, WidgetStateHelpers_1.getWidgetState)(state, target.widgetId);
                const tabIndex = target.tabIndex;
                const tabs = [...targetWidget.tabs];
                tabs.splice(tabIndex, 0, action.id);
                state = (0, WidgetStateHelpers_1.updateWidgetState)(state, targetWidget.id, {
                    tabs,
                });
            }
            else if ((0, DropTargetState_1.isPanelDropTargetState)(target)) {
                state = (0, PanelStateHelpers_1.updatePanelState)(state, target.side, (draft) => {
                    draft.widgets.push(target.newWidgetId);
                    draft.collapsed = false;
                });
                state = (0, WidgetStateHelpers_1.addWidgetState)(state, target.newWidgetId, [action.id]);
            }
            else if ((0, DropTargetState_1.isSectionDropTargetState)(target)) {
                state = (0, PanelStateHelpers_1.updatePanelState)(state, target.side, (draft) => {
                    draft.widgets.splice(target.sectionIndex, 0, target.newWidgetId);
                    draft.collapsed = false;
                });
                state = (0, WidgetStateHelpers_1.addWidgetState)(state, target.newWidgetId, [action.id]);
            }
            else if ((0, DropTargetState_1.isWidgetDropTargetState)(target)) {
                (0, NineZoneStateHelpers_1.updateHomeOfToolSettingsWidget)(state, target.widgetId, state.draggedTab.home);
                const widget = (0, WidgetLocation_1.getWidgetLocation)(state, target.widgetId);
                if (widget && (0, WidgetLocation_1.isPanelWidgetLocation)(widget)) {
                    state = (0, PanelStateHelpers_1.updatePanelState)(state, widget.side, (draft) => {
                        draft.collapsed = false;
                    });
                }
                const targetWidget = (0, WidgetStateHelpers_1.getWidgetState)(state, target.widgetId);
                const tabIndex = targetWidget.tabs.length;
                const tabs = [...targetWidget.tabs];
                tabs.splice(tabIndex, 0, action.id);
                state = (0, WidgetStateHelpers_1.updateWidgetState)(state, targetWidget.id, {
                    tabs,
                });
            }
            else {
                const tab = state.tabs[state.draggedTab.tabId];
                const nzBounds = core_react_1.Rectangle.createFromSize(state.size);
                const bounds = core_react_1.Rectangle.createFromSize(tab.preferredFloatingWidgetSize || target.size).offset(state.draggedTab.position);
                const containedBounds = bounds.containIn(nzBounds);
                const userSized = tab.userSized ||
                    (tab.isFloatingWidgetResizable && !!tab.preferredFloatingWidgetSize);
                state = (0, WidgetStateHelpers_1.addFloatingWidget)(state, target.newFloatingWidgetId, [action.id], {
                    bounds: containedBounds,
                    home: state.draggedTab.home,
                    userSized,
                });
            }
            return (0, immer_1.produce)(state, (draft) => {
                draft.draggedTab = undefined;
            });
        }
        case "WIDGET_TAB_POPOUT": {
            const { id, position, size } = action;
            const location = (0, TabLocation_1.getTabLocation)(state, id);
            if (location && (0, TabLocation_1.isPopoutTabLocation)(location))
                return state;
            const savedTab = state.savedTabs.byId[id];
            const tab = state.tabs[id];
            let contentHeight = 800;
            let contentWidth = 600;
            if (tab.preferredFloatingWidgetSize) {
                contentWidth = tab.preferredFloatingWidgetSize.width;
                contentHeight = tab.preferredFloatingWidgetSize.height;
            }
            else {
                const popoutContentContainer = document.getElementById(`content-container:${id}`);
                if (popoutContentContainer !== null) {
                    contentWidth = popoutContentContainer.offsetWidth + 20;
                    contentHeight = popoutContentContainer.offsetHeight + 20;
                }
            }
            let preferredBounds = savedTab?.popoutBounds
                ? core_react_1.Rectangle.create(savedTab.popoutBounds)
                : core_react_1.Rectangle.createFromSize({
                    height: contentHeight,
                    width: contentWidth,
                });
            if (size)
                preferredBounds = preferredBounds.setSize(size);
            if (position)
                preferredBounds = preferredBounds.setPosition(position);
            const popoutWidgetId = (0, NineZone_1.getUniqueId)();
            let home;
            if (location && (0, TabLocation_1.isPanelTabLocation)(location)) {
                const panel = state.panels[location.side];
                const widgetIndex = panel.widgets.indexOf(location.widgetId);
                home = {
                    side: location.side,
                    widgetId: location.widgetId,
                    widgetIndex,
                };
            }
            else if (location && (0, TabLocation_1.isFloatingTabLocation)(location)) {
                const floatingWidget = state.floatingWidgets.byId[location.floatingWidgetId];
                home = {
                    widgetId: floatingWidget.id,
                    floatingWidget,
                };
            }
            state = (0, TabStateHelpers_1.removeTabFromWidget)(state, id);
            return (0, WidgetStateHelpers_1.addPopoutWidget)(state, popoutWidgetId, [id], {
                bounds: preferredBounds.toProps(),
                home,
            });
        }
        case "WIDGET_TAB_HIDE": {
            return hideTab(state, action.id);
        }
        case "WIDGET_TAB_REMOVE": {
            // Save tab state.
            state = hideTab(state, action.id);
            // Remove tab.
            return (0, TabStateHelpers_1.removeTab)(state, action.id);
        }
        case "WIDGET_TAB_SET_LABEL": {
            return (0, TabStateHelpers_1.updateTabState)(state, action.id, (draft) => {
                draft.label = action.label;
            });
        }
        case "WIDGET_TAB_OPEN": {
            return openWidgetTab(state, action.id);
        }
        case "WIDGET_TAB_CLOSE": {
            const { id } = action;
            if (state.toolSettings?.tabId === id &&
                state.toolSettings.type === "docked") {
                return state;
            }
            let location;
            [state, location] = unhideTab(state, id);
            // TODO: should change activeTabId of a widget with multiple tabs.
            const widget = state.widgets[location.widgetId];
            if ((0, TabLocation_1.isFloatingTabLocation)(location) && id === widget.activeTabId) {
                state = (0, WidgetStateHelpers_1.updateWidgetState)(state, widget.id, {
                    minimized: true,
                });
            }
            return state;
        }
        case "WIDGET_TAB_FLOAT": {
            const { id, position, size } = action;
            let location;
            [state, location] = unhideTab(state, id);
            if ((0, TabLocation_1.isFloatingTabLocation)(location))
                return state;
            const tab = state.tabs[id];
            const preferredSize = size ??
                tab.preferredFloatingWidgetSize ?? { height: 400, width: 400 };
            const preferredPosition = position ?? { x: 50, y: 100 };
            const preferredBounds = core_react_1.Rectangle.createFromSize(preferredSize).offset(preferredPosition);
            const nzBounds = core_react_1.Rectangle.createFromSize(state.size);
            const containedBounds = preferredBounds.containIn(nzBounds);
            const userSized = tab.userSized ||
                (tab.isFloatingWidgetResizable && !!tab.preferredFloatingWidgetSize);
            if ((0, TabLocation_1.isPanelTabLocation)(location)) {
                const panel = state.panels[location.side];
                const widgetIndex = panel.widgets.indexOf(location.widgetId);
                state = (0, TabStateHelpers_1.updateTabState)(state, id, (draft) => {
                    (0, NineZoneStateHelpers_1.initSizeProps)(draft, "preferredFloatingWidgetSize", preferredSize);
                });
                state = (0, TabStateHelpers_1.removeTabFromWidget)(state, id);
                state = (0, WidgetStateHelpers_1.addFloatingWidget)(state, id, [id], {
                    bounds: containedBounds,
                    home: {
                        side: location.side,
                        widgetId: location.widgetId,
                        widgetIndex,
                    },
                    userSized,
                });
            }
            else {
                const popoutWidgetId = location.popoutWidgetId;
                const popoutWidget = state.popoutWidgets.byId[popoutWidgetId];
                const widget = state.widgets[popoutWidgetId];
                state = (0, WidgetStateHelpers_1.removePopoutWidget)(state, popoutWidgetId);
                const bounds = popoutWidget.bounds;
                const home = popoutWidget.home;
                state = (0, WidgetStateHelpers_1.addFloatingWidget)(state, popoutWidgetId, [id], {
                    bounds,
                    home: (0, WidgetRestoreState_1.isPanelWidgetRestoreState)(home)
                        ? home
                        : home.floatingWidget.home,
                }, widget);
            }
            const isToolSettings = state.toolSettings?.tabId === id;
            if (isToolSettings) {
                state = (0, immer_1.produce)(state, (draft) => {
                    (0, core_bentley_1.assert)(!!draft.toolSettings);
                    draft.toolSettings.type = "widget";
                });
            }
            return state;
        }
        case "WIDGET_TAB_SET_POPOUT_BOUNDS": {
            return (0, TabStateHelpers_1.updateSavedTabState)(state, action.id, (draft) => {
                (0, NineZoneStateHelpers_1.initRectangleProps)(draft, "popoutBounds", action.bounds);
            });
        }
        case "WIDGET_TAB_SHOW": {
            return showWidgetTab(state, action.id);
        }
        case "WIDGET_TAB_UNLOAD": {
            state = hideTab(state, action.id);
            return (0, TabStateHelpers_1.updateTabState)(state, action.id, (draft) => {
                draft.unloaded = true;
            });
        }
        case "WIDGET_TAB_EXPAND": {
            state = showWidgetTab(state, action.id);
            const location = (0, TabLocation_1.getTabLocation)(state, action.id);
            if (location && (0, TabLocation_1.isPanelTabLocation)(location)) {
                state = (0, PanelStateHelpers_1.updatePanelState)(state, location.side, (draft) => {
                    draft.splitterPercent =
                        draft.widgets.findIndex((wId) => wId === location.widgetId) === 0
                            ? 100
                            : 0;
                });
            }
            return state;
        }
        case "WIDGET_TAB_UPDATE": {
            return (0, TabStateHelpers_1.updateTabState)(state, action.id, (draft) => {
                for (const [key, val] of Object.entries(action.overrides)) {
                    draft[key] = val;
                }
            });
        }
        case "TOOL_SETTINGS_DRAG_START": {
            if (!state.toolSettings)
                return state;
            if (state.toolSettings.type === "widget")
                return state;
            const { newFloatingWidgetId } = action;
            const tabId = state.toolSettings.tabId;
            const tab = state.tabs[tabId];
            const size = tab.preferredFloatingWidgetSize || {
                height: 200,
                width: 300,
            };
            state = (0, WidgetStateHelpers_1.addFloatingWidget)(state, newFloatingWidgetId, [tabId], {
                bounds: core_react_1.Rectangle.createFromSize(size).toProps(),
            });
            return (0, immer_1.produce)(state, (draft) => {
                (0, core_bentley_1.assert)(!!draft.toolSettings);
                draft.toolSettings.type = "widget";
            });
        }
        case "TOOL_SETTINGS_DOCK": {
            if (!state.toolSettings)
                return state;
            if (state.toolSettings.type === "docked")
                return state;
            state = (0, TabStateHelpers_1.removeTabFromWidget)(state, state.toolSettings.tabId);
            return (0, immer_1.produce)(state, (draft) => {
                (0, core_bentley_1.assert)(!!draft.toolSettings);
                draft.toolSettings.type = "docked";
            });
        }
        case "WIDGET_DEF_ADD": {
            state = (0, TabStateHelpers_1.addTab)(state, action.id, action.overrides);
            const savedTab = state.savedTabs.byId[action.id];
            if (savedTab) {
                // Restore to saved state.
                return (0, TabStateHelpers_1.addRemovedTab)(state, action.id);
            }
            // Add to a floating widget.
            if (action.location === "floating") {
                // Add to an existing floating widget.
                if (action.floatingWidget.id in state.widgets) {
                    return (0, TabStateHelpers_1.addTabToWidget)(state, action.id, action.floatingWidget.id);
                }
                const size = action.overrides?.preferredFloatingWidgetSize ?? {
                    height: 200,
                    width: 300,
                };
                const position = action.floatingWidget.preferredPosition ?? {
                    x: (state.size.width - size.width) / 2,
                    y: (state.size.height - size.height) / 2,
                };
                const nzBounds = core_react_1.Rectangle.createFromSize(state.size);
                const bounds = core_react_1.Rectangle.createFromSize(size).offset(position);
                const containedBounds = bounds.containIn(nzBounds);
                const userSized = !!action.overrides?.preferredFloatingWidgetSize;
                return (0, WidgetStateHelpers_1.addFloatingWidget)(state, action.floatingWidget.id, [action.id], {
                    bounds: containedBounds.toProps(),
                    home: {
                        side: action.panelSection.side,
                        widgetId: action.panelSection.id,
                        widgetIndex: 0,
                    },
                    userSized,
                });
            }
            // Add to a panel section.
            const side = action.panelSection.side;
            // Add to an existing panel section.
            if (action.panelSection.id in state.widgets) {
                return (0, TabStateHelpers_1.addTabToWidget)(state, action.id, action.panelSection.id);
            }
            const panel = state.panels[side];
            // Add to a new panel section.
            if (panel.widgets.length < panel.maxWidgetCount) {
                return (0, PanelStateHelpers_1.addPanelWidget)(state, side, action.panelSection.id, [action.id]);
            }
            // Can't add additional sections, add to an existing one.
            const sectionIndex = Math.min(action.panelSection.index, panel.widgets.length - 1);
            const existingSectionId = panel.widgets[sectionIndex];
            return (0, TabStateHelpers_1.addTabToWidget)(state, action.id, existingSectionId);
        }
        case "WIDGET_DEF_ADD_TOOL_SETTINGS": {
            state = (0, TabStateHelpers_1.addTab)(state, action.id, action.overrides);
            return (0, ToolSettingsStateHelpers_1.addDockedToolSettings)(state, action.id);
        }
    }
    return state;
}
exports.NineZoneStateReducer = NineZoneStateReducer;
function openWidgetTab(state, id) {
    if (state.toolSettings?.tabId === id &&
        state.toolSettings.type === "docked") {
        return (0, immer_1.produce)(state, (draft) => {
            (0, core_bentley_1.assert)(draft.toolSettings.type === "docked");
            draft.toolSettings.hidden = false;
        });
    }
    let location;
    [state, location] = unhideTab(state, id);
    return (0, immer_1.produce)(state, (draft) => {
        const widget = draft.widgets[location.widgetId];
        widget.minimized = false;
        widget.activeTabId = id;
        if ((0, TabLocation_1.isPanelTabLocation)(location)) {
            const panel = draft.panels[location.side];
            panel.collapsed = false;
            if (undefined === panel.size || 0 === panel.size) {
                panel.size = panel.minSize ?? 200;
            }
        }
    });
}
function showWidgetTab(state, id) {
    state = openWidgetTab(state, id);
    const location = (0, TabLocation_1.getTabLocation)(state, id);
    if (!location)
        return state;
    state = (0, WidgetStateHelpers_1.updateWidgetState)(state, location.widgetId, {
        activeTabId: id,
        minimized: false,
    });
    if ((0, TabLocation_1.isPanelTabLocation)(location)) {
        state = (0, PanelStateHelpers_1.updatePanelState)(state, location.side, (draft) => {
            draft.collapsed = false;
        });
    }
    if ((0, TabLocation_1.isFloatingTabLocation)(location)) {
        state = (0, WidgetStateHelpers_1.floatingWidgetBringToFront)(state, location.floatingWidgetId);
    }
    return state;
}
function unhideTab(state, id) {
    let location = (0, TabLocation_1.getTabLocation)(state, id);
    if (!location) {
        state = (0, TabStateHelpers_1.addRemovedTab)(state, id);
        location = (0, TabLocation_1.getTabLocation)(state, id);
        (0, core_bentley_1.assert)(!!location);
    }
    state = (0, TabStateHelpers_1.updateTabState)(state, id, (draft) => {
        draft.unloaded = false;
    });
    return [state, location];
}
function hideTab(state, id) {
    state = (0, immer_1.produce)(state, (draft) => {
        if (!draft.toolSettings)
            return;
        const isToolSettings = draft.toolSettings.tabId === id;
        if (isToolSettings && draft.toolSettings.type === "docked") {
            draft.toolSettings.hidden = true;
        }
    });
    state = (0, TabStateHelpers_1.updateTabState)(state, id, (draft) => {
        draft.unloaded = false;
    });
    const location = (0, TabLocation_1.getTabLocation)(state, id);
    if (!location)
        return state;
    const widgetId = location.widgetId;
    const tabIndex = state.widgets[widgetId].tabs.indexOf(id);
    if ((0, TabLocation_1.isFloatingTabLocation)(location)) {
        const floatingWidget = state.floatingWidgets.byId[widgetId];
        // widgetDef.setFloatingContainerId(location.floatingWidgetId);
        state = (0, TabStateHelpers_1.updateSavedTabState)(state, id, (draft) => {
            draft.home = {
                widgetId,
                tabIndex,
                floatingWidget,
            };
        });
    }
    else if ((0, TabLocation_1.isPanelTabLocation)(location)) {
        const side = location.side;
        const widgetIndex = state.panels[side].widgets.indexOf(widgetId);
        state = (0, TabStateHelpers_1.updateSavedTabState)(state, id, (draft) => {
            draft.home = {
                widgetId,
                side,
                widgetIndex,
                tabIndex,
            };
        });
    }
    return (0, TabStateHelpers_1.removeTabFromWidget)(state, id);
}
//# sourceMappingURL=NineZoneStateReducer.js.map