/*---------------------------------------------------------------------------------------------
 * Copyright (c) Bentley Systems, Incorporated. All rights reserved.
 * See LICENSE.md in the project root for license terms and full copyright notice.
 *--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Widget
 */
import { UiError, UiEvent } from "@itwin/appui-abstract";
import { ConfigurableCreateInfo, ConfigurableUiControlType, } from "../configurableui/ConfigurableUiControl";
import { UiFramework } from "../UiFramework";
import { PropsHelper } from "../utils/PropsHelper";
import { IconHelper } from "@itwin/core-react";
import { WidgetState } from "./WidgetState";
import { StagePanelLocation } from "../stagepanels/StagePanelLocation";
import { StatusBarWidgetComposerControl } from "./StatusBarWidgetComposerControl";
import { getTabLocation, isFloatingTabLocation, isPanelTabLocation, isPopoutTabLocation, } from "../layout/state/TabLocation";
import { IModelApp } from "@itwin/core-frontend";
/** Widget State Changed Event class.
 * @public
 * @deprecated in 4.13.0. This class should not be used by applications to instantiate objects.
 */
// eslint-disable-next-line deprecation/deprecation
export class WidgetStateChangedEvent extends UiEvent {
}
/** Widget type enum.
 * @public
 */
export var WidgetType;
(function (WidgetType) {
    WidgetType[WidgetType["Tool"] = 0] = "Tool";
    WidgetType[WidgetType["Navigation"] = 1] = "Navigation";
    WidgetType[WidgetType["Rectangular"] = 2] = "Rectangular";
    WidgetType[WidgetType["ToolSettings"] = 3] = "ToolSettings";
    WidgetType[WidgetType["StatusBar"] = 4] = "StatusBar";
})(WidgetType || (WidgetType = {}));
// -----------------------------------------------------------------------------
/** A Widget Definition in the 9-Zone Layout system.
 * @public
 */
export class WidgetDef {
    get state() {
        const frontstageDef = UiFramework.frontstages.activeFrontstageDef;
        const nineZone = frontstageDef?.nineZoneState;
        if (!nineZone)
            return this.defaultState;
        if (!frontstageDef.findWidgetDef(this.id))
            return this.defaultState;
        return getWidgetState(this, nineZone);
    }
    get id() {
        return this._id;
    }
    get priority() {
        return this._priority;
    }
    get isFloatingStateSupported() {
        if (!this.initialConfig)
            return true;
        const allowedPanels = this.initialConfig.allowedPanels;
        if (allowedPanels && allowedPanels.length === 0) {
            return true;
        }
        const canFloat = this.initialConfig.canFloat;
        if (canFloat === undefined)
            return true;
        return !!canFloat;
    }
    get isFloatingStateWindowResizable() {
        const canFloat = this.initialConfig?.canFloat;
        if (typeof canFloat === "object") {
            return canFloat.isResizable === undefined ? true : canFloat.isResizable;
        }
        return true;
    }
    get isToolSettings() {
        return this._widgetType === WidgetType.ToolSettings;
    }
    get isStatusBar() {
        return this._widgetType === WidgetType.StatusBar;
    }
    get stateChanged() {
        return this._stateChanged;
    }
    get applicationData() {
        return this._applicationData;
    }
    get isFloating() {
        return this.state === WidgetState.Floating;
    }
    /** @deprecated in 4.16.0. Use {@link Widget.iconNode} instead. */
    // eslint-disable-next-line deprecation/deprecation
    get iconSpec() {
        // eslint-disable-next-line deprecation/deprecation
        return this._iconSpec === IconHelper.reactIconKey
            ? IconHelper.getIconReactNode(this._iconSpec, this._internalData) // eslint-disable-line deprecation/deprecation
            : this._iconSpec;
    }
    // eslint-disable-next-line deprecation/deprecation
    set iconSpec(spec) {
        // Setter is deprecated as well: ae-setter-with-docs.
        this._iconSpec = this._internalData
            ? IconHelper.getIconData(spec, this._internalData) // eslint-disable-line deprecation/deprecation
            : spec;
    }
    /** @deprecated in 4.16.0. Use `badgeKind` instead. */
    // eslint-disable-next-line deprecation/deprecation
    get badgeType() {
        return this._badge;
    }
    // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
    get badgeKind() {
        return this._badgeKind;
    }
    get initialConfig() {
        return this._initialConfig;
    }
    get widgetType() {
        return this._widgetType;
    }
    set widgetType(type) {
        this._widgetType = type;
    }
    /** @internal */
    get defaultFloatingPosition() {
        return this._defaultFloatingPosition;
    }
    set defaultFloatingPosition(position) {
        this._defaultFloatingPosition = position;
    }
    /** @internal */
    get defaultFloatingSize() {
        return this._defaultFloatingSize;
    }
    set defaultFloatingSize(size) {
        this._defaultFloatingSize = size;
    }
    /** @internal */
    get defaultState() {
        return this._defaultState;
    }
    constructor() {
        this._label = "";
        this._tooltip = "";
        this._defaultState = WidgetState.Closed;
        this._priority = 0;
        this._stateChanged = false;
        this._widgetType = WidgetType.Rectangular;
        WidgetDef._sId++;
        this._id = `Widget-${WidgetDef._sId}`;
    }
    /** @internal */
    static create(config, type = WidgetType.Rectangular) {
        const def = new WidgetDef();
        def.initializeFromConfig(config, type);
        return def;
    }
    initializeFromConfig(config, type) {
        this._widgetType = type;
        this._initialConfig = config;
        this._id = config.id;
        if (config.label)
            this._label = config.label;
        else if (config.labelKey)
            this._label = IModelApp.localization.getLocalizedString(config.labelKey);
        else if (type === WidgetType.ToolSettings)
            this._label = "Tool Settings";
        this.setCanPopout(config.canPopout);
        const canFloat = config.canFloat;
        if (typeof canFloat === "object") {
            this.setFloatingContainerId(canFloat.containerId);
            this.defaultFloatingPosition = canFloat.defaultPosition;
            this._hideWithUiWhenFloating = !!canFloat.hideWithUi;
            this._defaultFloatingSize = canFloat.defaultSize;
        }
        if ("allowedPanels" in config) {
            this.allowedPanelTargets = config.allowedPanels;
        }
        else if (type === WidgetType.ToolSettings)
            this.allowedPanelTargets = [
                StagePanelLocation.Bottom,
                StagePanelLocation.Left,
                StagePanelLocation.Right,
            ];
        if (config.priority !== undefined)
            this._priority = config.priority;
        if (config.tooltip)
            this.setTooltip(config.tooltip);
        else if (config.tooltipKey)
            this._tooltip = IModelApp.localization.getLocalizedString(config.tooltipKey);
        if (config.defaultState !== undefined) {
            this._defaultState = config.defaultState;
        }
        if (config.allowedPanels &&
            config.allowedPanels.length === 0 &&
            config.defaultState === WidgetState.Open) {
            this._defaultState = WidgetState.Floating;
        }
        this._widgetReactNode = config.content;
        // eslint-disable-next-line deprecation/deprecation
        this._iconSpec = config.iconNode ?? config.icon;
        // eslint-disable-next-line deprecation/deprecation
        this._badge = config.badge;
        this._badgeKind = config.badgeKind;
        this._preferredPanelSize = config.preferredPanelSize;
    }
    /** @alpha */
    get preferredPanelSize() {
        return this._preferredPanelSize;
    }
    /** Get the label string */
    get label() {
        // eslint-disable-next-line deprecation/deprecation
        return PropsHelper.getStringFromSpec(this._label);
    }
    /** Set the label.
     * @param labelSpec A string or a function to get the string.
     */
    setLabel(labelSpec) {
        this._label = labelSpec; // TODO: handle ConditionalStringValue
        const frontstageDef = UiFramework.frontstages.activeFrontstageDef;
        if (!frontstageDef)
            return;
        // eslint-disable-next-line deprecation/deprecation
        const label = PropsHelper.getStringFromSpec(labelSpec);
        frontstageDef.dispatch({
            type: "WIDGET_TAB_SET_LABEL",
            id: this.id,
            label,
        });
    }
    /** Get the tooltip string */
    get tooltip() {
        // eslint-disable-next-line deprecation/deprecation
        return PropsHelper.getStringFromSpec(this._tooltip);
    }
    /** Set the tooltip.
     * @param v A string or a function to get the string.
     */
    setTooltip(v) {
        this._tooltip = v;
    }
    get reactNode() {
        if (!this._widgetReactNode) {
            // eslint-disable-next-line deprecation/deprecation
            const widgetControl = this.getWidgetControl(
            // eslint-disable-next-line deprecation/deprecation
            ConfigurableUiControlType.Widget);
            if (widgetControl && widgetControl.reactNode)
                this._widgetReactNode = widgetControl.reactNode;
        }
        return this._widgetReactNode;
    }
    set reactNode(node) {
        this._widgetReactNode = node;
    }
    setWidgetState(newState) {
        const frontstageDef = UiFramework.frontstages.activeFrontstageDef;
        const nineZone = frontstageDef?.nineZoneState;
        if (!nineZone || this.isStatusBar)
            return;
        if (!frontstageDef.findWidgetDef(this.id))
            return;
        switch (newState) {
            case WidgetState.Closed: {
                frontstageDef.dispatch({
                    type: "WIDGET_TAB_CLOSE",
                    id: this.id,
                });
                break;
            }
            case WidgetState.Floating: {
                frontstageDef.dispatch({
                    type: "WIDGET_TAB_FLOAT",
                    id: this.id,
                    position: this._defaultFloatingPosition,
                });
                break;
            }
            case WidgetState.Hidden: {
                frontstageDef.dispatch({
                    type: "WIDGET_TAB_HIDE",
                    id: this.id,
                });
                break;
            }
            case WidgetState.Open: {
                frontstageDef.dispatch({
                    type: "WIDGET_TAB_OPEN",
                    id: this.id,
                });
                break;
            }
            case WidgetState.Unloaded: {
                frontstageDef.dispatch({
                    type: "WIDGET_TAB_UNLOAD",
                    id: this.id,
                });
                break;
            }
        }
    }
    /** @internal */
    handleWidgetStateChanged(newState) {
        this._stateChanged = true;
        UiFramework.frontstages.onWidgetStateChangedEvent.emit({
            widgetDef: this,
            widgetState: newState,
        });
        this.onWidgetStateChanged();
    }
    setCanPopout(value) {
        this._canPopout = value;
    }
    get canPopout() {
        return this._canPopout;
    }
    setFloatingContainerId(value) {
        this._floatingContainerId = value;
    }
    get floatingContainerId() {
        return this._floatingContainerId;
    }
    canOpen() {
        return this.isFloating || this.isActive;
    }
    get isVisible() {
        return (WidgetState.Hidden !== this.state && WidgetState.Unloaded !== this.state);
    }
    get activeState() {
        return this.state;
    }
    get isActive() {
        return WidgetState.Open === this.activeState;
    }
    set hideWithUiWhenFloating(hide) {
        this._hideWithUiWhenFloating = !!hide;
    }
    get hideWithUiWhenFloating() {
        return !!this._hideWithUiWhenFloating;
    }
    get allowedPanelTargets() {
        return this._allowedPanelTargets;
    }
    set allowedPanelTargets(targets) {
        this._allowedPanelTargets = targets;
    }
    onWidgetStateChanged() {
        // eslint-disable-next-line deprecation/deprecation
        this.widgetControl && this.widgetControl.onWidgetStateChanged();
    }
    /** Overwrite to save transient DOM state (i.e. scroll offset). */
    saveTransientState() {
        // eslint-disable-next-line deprecation/deprecation
        this.widgetControl && this.widgetControl.saveTransientState();
        this._saveTransientState && this._saveTransientState();
    }
    /** Overwrite to restore transient DOM state.
     * @note Return true if the state is restored or the Widget will remount.
     */
    restoreTransientState() {
        let result = true;
        // eslint-disable-next-line deprecation/deprecation
        if (this.widgetControl || this._restoreTransientState) {
            let result1 = false, result2 = false;
            // eslint-disable-next-line deprecation/deprecation
            if (this.widgetControl)
                // eslint-disable-next-line deprecation/deprecation
                result1 = this.widgetControl.restoreTransientState();
            if (this._restoreTransientState)
                result2 = this._restoreTransientState();
            result = !(result1 || result2);
        }
        return result;
    }
    /** Opens the widget and makes it visible to the user.
     * @note Opens the stage panel if needed.
     * @note Brings the floating widget to the front.
     * @note Brings the window of the popout widget to the front (if allowed by the browser).
     * @public
     */
    show() {
        const frontstageDef = UiFramework.frontstages.activeFrontstageDef;
        const nineZone = frontstageDef?.nineZoneState;
        if (!nineZone)
            return;
        if (!frontstageDef.findWidgetDef(this.id))
            return;
        const tabLocation = getTabLocation(nineZone, this.id);
        if (tabLocation && isPopoutTabLocation(tabLocation)) {
            const testWindow = UiFramework.childWindows.find(tabLocation.popoutWidgetId);
            // Try to bring the window of the popout widget to the front.
            testWindow?.window.focus();
        }
        frontstageDef.dispatch({
            type: "WIDGET_TAB_SHOW",
            id: this.id,
        });
    }
    /** Opens the widget and expands it to fill full size of the stage panel.
     * @public
     */
    expand() {
        const frontstageDef = UiFramework.frontstages.activeFrontstageDef;
        const nineZone = frontstageDef?.nineZoneState;
        if (!nineZone)
            return;
        if (!frontstageDef.findWidgetDef(this.id))
            return;
        frontstageDef.dispatch({
            type: "WIDGET_TAB_EXPAND",
            id: this.id,
        });
    }
    /* eslint-disable deprecation/deprecation */
    /** @deprecated in 4.16.0. Uses a deprecated type {@link ConfigurableUiControlConstructor}. */
    get classId() {
        return undefined;
    }
    /** @deprecated in 4.16.0. Returns an instance of a deprecated type {@link WidgetControl}. */
    get widgetControl() {
        return this._widgetControl;
    }
    /** @deprecated in 4.16.0. Returns an instance of a deprecated type {@link WidgetControl}. */
    getWidgetControl(type) {
        if (!this._widgetControl && this.classId) {
            let usedClassId = "";
            if (typeof this.classId === "string") {
                if (this.classId)
                    this._widgetControl = UiFramework.controls.create(this.classId, this.id, this.applicationData);
                usedClassId = this.classId;
            }
            else {
                const info = new ConfigurableCreateInfo(this.classId.name, this.id, this.id);
                usedClassId = this.classId.name;
                this._widgetControl = new this.classId(info, this.applicationData);
            }
            if (this._widgetControl) {
                if (this._widgetControl.getType() !== type) {
                    // eslint-disable-next-line deprecation/deprecation
                    throw new UiError(UiFramework.loggerCategory(this), `getWidgetControl: '${usedClassId}' is NOT a ${type}; it is a ${this._widgetControl.getType()}`);
                }
                this._widgetControl.widgetDef = this;
                this._widgetControl.initialize();
            }
        }
        if (!this._widgetControl && this.isStatusBar) {
            const info = new ConfigurableCreateInfo("StatusBarWidgetComposerControl", StatusBarWidgetComposerControl.controlId, StatusBarWidgetComposerControl.controlId);
            this._widgetControl = new StatusBarWidgetComposerControl(info, undefined);
            this._widgetControl.widgetDef = this;
            this._widgetControl.initialize();
        }
        return this._widgetControl;
    }
}
WidgetDef._sId = 0;
/** @internal */
export function getWidgetState(widgetDef, nineZone) {
    const tab = nineZone.tabs[widgetDef.id];
    if (tab && tab.unloaded) {
        return WidgetState.Unloaded;
    }
    if (nineZone.draggedTab?.tabId === widgetDef.id) {
        return WidgetState.Closed;
    }
    const toolSettingsTabId = nineZone.toolSettings?.tabId;
    if (toolSettingsTabId === widgetDef.id &&
        nineZone.toolSettings?.type === "docked") {
        return nineZone.toolSettings.hidden ? WidgetState.Hidden : WidgetState.Open;
    }
    const location = getTabLocation(nineZone, widgetDef.id);
    if (!location) {
        return WidgetState.Hidden;
    }
    if (isFloatingTabLocation(location)) {
        return WidgetState.Floating;
    }
    if (isPanelTabLocation(location)) {
        const panel = nineZone.panels[location.side];
        if (panel.collapsed || undefined === panel.size || 0 === panel.size)
            return WidgetState.Closed;
    }
    const widget = nineZone.widgets[location.widgetId];
    if (widget.minimized || widgetDef.id !== widget.activeTabId)
        return WidgetState.Closed;
    return WidgetState.Open;
}
//# sourceMappingURL=WidgetDef.js.map