/*!
 * Copyright 2017 - 2020 by ChartIQ, Inc.
 * All rights reserved.
 */
/**
 * WindowClient is primarily responsible for managing window state (the window's location and size) and app state (data inside of your app).
 * @module WindowClient
 */
/**
This is how we want our API to work going forward, the way the world does it: import { processAndSet } from "configClient"
```
export const processAndSet = () => { ... }
```

This module's single exported object gives us backward compatibility when our core code does this: import { ConfigClient } from "configClient"
and provides the object that is attached to FSBL.Clients. This export should be kept as clean and simple as possible.
```
export const ConfigClient = {
   processAndSet
}
```

The default export gives us backward compatibility where our core code does this: import ConfigClient from "configClient"
This can be eliminated when our core core is converted to normal imports as in the first example.
```
export default ConfigClient;
```
*/
import { System } from "../common/system";
import { Logger } from "./logger";
import { RouterClient } from "./routerClient";
import { FEAGlobals } from "../common/Globals";
import { getDesktopBoundingBox as getDesktopBoundingBoxFromUtil, isPointInBox as isPointInBoxFromUtil, isMouseOverDOMElement as isMouseOverDOMElementFromUtil, } from "../common/util";
import { getMonitor, getWhichMonitorClientSide } from "../common/Monitors";
import { deprecatedSetActive, deprecatedGetWindowNameForDocking } from "../deprecated/deprecatedFunctions";
import { cacheInitialBounds as cacheInitialBoundsFromStartup } from "./Startup/windowStartup";
import { singleton } from "../common/Singleton";
import SystemManagerClient from "../common/systemManagerClient";
import { FinsembleWindow } from "../common/FinsembleWindow";
import { actions, emptyStore } from "../platform/services/window/modules/actions";
import { getRemoteStoreAsSingleton, getRemoteState } from "../common/redux/getRemoteStore";
/**
 * Add a local hot key for reloading; apps with BrowserView title bars will not refresh
 * if the focus is on the web content and the user presses control-r.
 */
const modifyReload = () => {
    // This is a workaround for correct content reloading on CTRL+R.
    // The Electron build-in reloading for CTRL+R happens faster than the local hotkey will be triggered.
    // Only add if this is a web content which has a BrowserView title bar
    if (!FEAGlobals.fin.isTitlebarWindow() && FEAGlobals.fin.isBrowserView()) {
        document.addEventListener("keydown", (e) => {
            if (e.ctrlKey && e.key.toLowerCase() === "r") {
                e.preventDefault();
                e.stopPropagation();
                FEAGlobals.finsembleWindow.reload();
            }
        });
    }
};
/**
 * The WindowClientController is a singleton which serves as the backing for the WindowClient export. Even though WindowClient
 * is exported, there can still be more than one instance when running with an FEA preload. In these circumstances, the singleton
 * nature of the controller ensures that both instances have access to the same static data, and that there are only ever
 * one set of router messages/event listeners.
 *
 * WindowClient accesses the WindowClientController's internal objects using getters and setters. This allows multiple copies
 * of WindowClient to each maintain a reference to the singleton's members, guaranteeing consistency.
 *
 * The WindowClientController must be started from an entry point (FSBLDesktop or FSBLService).
 */
class WindowClientController {
    constructor() {
        this.options = {};
        this.title = null;
        this.windowGroups = [];
    }
    /**
     * Handler for group updates from the window service.  Stores the groups that this window is in,
     * if any.
     * @param err the error, if any
     * @param res the received updated group data
     */
    groupUpdateHandler(err, res) {
        if (err) {
            Logger.error(err);
            return;
        }
        if (!res.data || !res.data.groupData)
            return;
        this.windowGroups = Object.values(res.data.groupData).filter((group) => group.windowNames.includes(deprecatedGetWindowNameForDocking(FEAGlobals.finsembleWindow)));
    }
    setStartupData(systemStartupData) {
        this.options = systemStartupData;
    }
    async start() {
        await SystemManagerClient.waitForStartup("windowService");
        RouterClient.subscribe("Finsemble.WorkspaceService.groupUpdate", (groupUpdateSubscribeErr, res) => this.groupUpdateHandler(groupUpdateSubscribeErr, res));
        // On Blur remove the border from window
        FEAGlobals.finsembleWindow.addEventListener("blurred", () => {
            deprecatedSetActive(false);
        });
        // On focus add a border to the window
        FEAGlobals.finsembleWindow.addEventListener("focused", () => {
            deprecatedSetActive(true);
        });
        // Add reload handlers for non-titlebar instances
        // The reload handler was moved to windowStartup and also made to only
        // work with titlebars; this was probably an oversight.
        modifyReload();
    }
}
/**
 * @ignore
 */
export const getControllerInstance = () => singleton("WindowClient", WindowClientController);
/**
 * @deprecated
 * Returns a list of the groups this window is in, if any.
 */
const getWindowGroups = () => {
    Logger.deprecated("getWindowGroups() is deprecated and will be removed in a future release.");
    const controller = getControllerInstance();
    return controller.windowGroups;
};
/**
 * @language javascript, java, dotnet
 * Closes window. Defaults are to remove the window from the workspace if the user presses the X button, but not if the window is closed via an app-level request (e.g., switching workspaces, so all windows need to close).
 *
 * @deprecated - Use of parameters has been deprecated, and will be removed in an upcoming version.
 *
 * ```javascript
 * //Close window and remove from workspace (e.g., user closes the window).
 * FSBL.Clients.WindowClient.close({ removeFromWorkspace: true, closeWindow: true });
 * //Close window and keep in workspace (e.g., application requests that all windows close themselves).
 * FSBL.Clients.WindowClient.close({ removeFromWorkspace: false, closeWindow: false });
 * ```
 * @param {object} params
 * @param {boolean} params.removeFromWorkspace Whether to remove the window from the workspace.
 * @param {boolean} params.closeWindow Whether to close the window. On shutdown this method is called, but the Window Service actually closes the window.
 * @param {boolean} params.userInitiated Whether the user clicked the X, or if the system asked the window to close.
 * @param {function} cb The callback to be invoked after the method completes successfully.
 */
export const close = (params, cb) => {
    if (!params) {
        params = { removeFromWorkspace: true, closeWindow: true };
    }
    else {
        // Note: It has been deprecated to use parameters. Normally, we would use Logger.deprecate() here, but the parameters are currently being used internally.
        // If we were to include Logger.deprecate(), we would flood the central logger. So, we're just going to document it as deprecated. The parameters will be
        // unnecessary for internal usage once we move to io.CD.
    }
    return FEAGlobals.finsembleWindow.close(params, cb);
};
/**
 * @language javascript, java, dotnet
 * Retrieves the window's title.
 *
 * ```javascript
 *	// Get the current window's title
 * await FSBL.Clients.WindowClient.getWindowTitle();
 *
 * 	// Get a different window's title
 * await FSBL.Clients.WindowClient.getWindowTitle("windowName-foo-bar");
 * ```
 *
 * @param windowName
 * @returns {Promise<String|null>} title
 */
export const getWindowTitle = async (windowName) => {
    var _a, _b, _c;
    windowName = windowName || ((_a = FEAGlobals.finsembleWindow) === null || _a === void 0 ? void 0 : _a.name) || window.name;
    const state = (await getRemoteState({
        server: "@@finsemble/remoteRedux/WindowServiceStore",
        slice: "windowTitleBar",
    }));
    return (_c = (_b = state.windowTitleBar.windows[windowName]) === null || _b === void 0 ? void 0 : _b.title) !== null && _c !== void 0 ? _c : null;
};
/**
 * This function retrieves the dimensions of the monitor that the window is on. It's currently used in the <a href="/docs/reference/typedocs/modules/LauncherClient">LauncherClient</a>.
 * @param {function} callback
 */
const retrieveMonitorDimensions = async (cb) => {
    Logger.deprecated("WindowClient.retrieveMonitorDimensions() is deprecated and will be removed in a future release.");
    const monitorInfo = await getMonitor();
    FEAGlobals.finsembleWindow.updateOptions({
        options: { monitorDimensions: monitorInfo.monitorRect },
    });
    cb === null || cb === void 0 ? void 0 : cb(monitorInfo.monitorRect);
};
/**
 * Gets the bounds for the window on startup and saves them to the workspace.
 */
const cacheInitialBounds = async () => {
    Logger.deprecated("WindowClient.cacheInitialBounds() is deprecated and will be removed in a future version.");
    cacheInitialBoundsFromStartup();
};
/**
 * @deprecated
 * Returns windowBounds as of the last save.
 * @returns {object}
 * @todo deprecate and remove from linkerClient
 */
const getWindowBounds = () => {
    Logger.deprecated("WindowClient.getWindowBounds() is deprecated and will be removed in a future version.");
    return {
        top: FEAGlobals.finsembleWindow.windowOptions.defaultTop,
        left: FEAGlobals.finsembleWindow.windowOptions.defaultLeft,
        width: FEAGlobals.finsembleWindow.windowOptions.defaultWidth,
        height: FEAGlobals.finsembleWindow.windowOptions.defaultHeight,
    };
};
/**
 *
 * Saves the window's state. Rarely called manually, as it's called every time your window moves.
 *
 * The code below is the bulk of our listener for the <code>bounds-changed</code> event from the window. Every time the <code>bounds-changed</code> event is fired (when the window is resized or moved), we save the window's state. The first few lines just prevent the window from being dropped behind the toolbar.
 * ```javascript
 * finWindow.addEventListener('disabled-frame-bounds-changed', function (bounds) {
 * 	if (bounds.top < 45) {
 *		finWindow.moveTo(bounds.left, 45);
 *		return;
 *	}
 *	self.saveWindowBounds(bounds);
 * ```
 * @param {Object} bounds optional param.
 * @param {boolean} setActiveWorkspaceDirty
 *});
 */
const saveWindowBounds = (bounds, setActiveWorkspaceDirty) => {
    Logger.system.debug("WINDOW LIFECYCLE:SavingBounds:", bounds, "setActiveWorkspaceDirty", setActiveWorkspaceDirty);
    if (typeof setActiveWorkspaceDirty === "undefined") {
        setActiveWorkspaceDirty = false;
    }
    if (!bounds) {
        return;
    }
    FEAGlobals.finsembleWindow.updateOptions({
        options: {
            top: Math.round(bounds.top),
            defaultTop: Math.round(bounds.top),
            left: Math.round(bounds.left),
            defaultLeft: Math.round(bounds.left),
            width: Math.round(bounds.width),
            defaultWidth: Math.round(bounds.width),
            height: Math.round(bounds.height),
            defaultHeight: Math.round(bounds.height),
        },
    });
    try {
        if (!FEAGlobals.finsembleWindow.windowOptions.customData.foreign.components["Window Manager"].persistWindowState) {
        }
    }
    catch (e) {
        // prop doesn't exist.
    }
};
/**
 * @language javascript, java, dotnet
 * Maximizes the window taking into account any claimed space on the monitor.
 *
 * ```javascript
 * FSBL.Clients.WindowClient.maximize();
 * ```
 * @param {function} cb Optional callback to be invoked after the method completes successfully.
 */
export const maximize = (cb) => FEAGlobals.finsembleWindow.maximize(null, cb);
/**
 * @language javascript, java, dotnet
 * Minimizes window.
 *
 * ```javascript
 * FSBL.Clients.WindowClient.minimize();
 * ```
 * @param {function} cb Optional callback to be invoked after the method completes successfully.
 */
export const minimize = (cb) => FEAGlobals.finsembleWindow.minimize(null, cb);
/**
 * @language javascript, java
 * Brings the window to the top of all other windows.
 *
 * ```javascript
 * FSBL.Clients.WindowClient.bringToFront();
 * ```
 */
export const bringToFront = (cb) => FEAGlobals.finsembleWindow.bringToFront({ forceFocus: true }, cb);
/**
 * @language javascript, java, dotnet
 * @deprecated Use [`bringToFront()`](#bringtofront) instead, which returns a promise.
 *
 * Brings the window to the top of all other windows
 *
 * This is a non-promise version for backward compatibility. Please use WindowClient.bringToFront()
 *
 * @deprecated Use `bringToFront()` instead, which returns a promise.
 */
export const bringWindowToFront = (cb) => {
    Logger.system.deprecated("WindowClient.bringWindowToFront() has been deprecated. Please use WindowClient.bringToFront() which returns a promise.");
    FEAGlobals.finsembleWindow.bringToFront({ forceFocus: true }, cb);
};
/**
 * @language javascript, java, dotnet
 * Sets whether window is always on top. By default, this is false.
 *
 * ```javascript
 * FSBL.Clients.WindowClient.setAlwaysOnTop(true);
 * ```
 * @param {boolean} alwaysOnTop The new mode for the window's alwaysOnTop option to be set to.
 * @param {function} cb Optional callback to be invoked after the method completes successfully.
 */
export const setAlwaysOnTop = (alwaysOnTop, cb) => FEAGlobals.finsembleWindow.setAlwaysOnTop({ alwaysOnTop }, cb);
/**
 * @language javascript, java, dotnet
 * Restores window from a maximized or minimized state.
 *
 * ```javascript
 * FSBL.Clients.WindowClient.restore();
 * ```
 * @param {function} cb Optional callback to be invoked after the method completes successfully.
 */
export const restore = (cb) => FEAGlobals.finsembleWindow.restore(null, cb);
/**
 * @language javascript, java
 * :::tip Important
 * _This feature is experimental. The signature may change in the future._
 * :::
 *
 * Sets an overlay image on the MS Windows taskbar, for instance to indicate activity.
 * (This is sometimes referred to as a "badge").
 *
 * The url must point to a 16x16 png image. Images of other sizes or types will not display.
 *
 * :::note
 * MacOS does not support taskbar overlay images. This function is safe to call
 * on MacOS but will not perform any function.
 * :::
 *
 * @param url - The url of the icon to use. Pass null to remove the overlay icon.
 */
export const setTaskbarIconOverlay = (url) => {
    FEAGlobals.fin.desktop.Window.setTaskbarIconOverlay({ iconURL: url });
};
/**
 * This function injects the header bar into all windows without frames that request it. This should only be used if you've decided not to use the provided <code>WindowClient.start()</code> method.
 *
 * **NOTE:** If you are using the Finsemble window title bar component, you do not need to call this function.
 */
const injectDOM = (headerHeight) => {
    Logger.system.deprecated("WindowClient.injectDOM() has been deprecated and will be removed in a future release");
    // for the aesthetics.
    if (document.getElementById("FSBLHeader")) {
        return;
    }
    // On slow loading components, the end user might have the opportunity to scroll the page before the window title bar is injected.
    // This triggers a chromium bug related to elements with position:fixed. Chromium loses track of where that element actually is on
    // the browser page. Chromium *thinks* the title bar is lower than it actually is, by the amount of pixels scrolled by the user.
    // The fix is to force the scroll position back to zero before we inject this fixed element.
    window.scrollTo(0, 0);
    // Now inject the window title bar
    const template = document.createElement("div");
    const style = headerHeight ? ` style=height:${headerHeight}` : "";
    template.innerHTML = `<div id="FSBLHeader"${style}></div>`;
    if (template.firstChild) {
        document.body.insertBefore(template.firstChild, document.body.firstChild);
    }
};
// returns Finsemble Window Object of current element or of element specified in given params
const getElementFinsembleWindow = async (params) => {
    if ((params === null || params === void 0 ? void 0 : params.windowName) && (params === null || params === void 0 ? void 0 : params.windowName.length) > 0) {
        const { wrap } = await FinsembleWindow.getInstance({ name: params.windowName });
        return wrap;
    }
    return FEAGlobals.finsembleWindow;
};
/**
 * @language javascript, java, dotnet
 * Given a field, this function retrieves app state. If no params are given, returns the full state.
 *
 * Here's how to retrieve data to restore the layout of our charts.
 * ```javascript
 * FSBL.Clients.WindowClient.getComponentState({
 *	 field: 'myChartLayout',
 * }, function (err, state) {
 * 	importLayout(state);
 * });
 *
 * FSBL.Clients.WindowClient.getComponentState({
 * 		fields: ['myChartLayout', 'chartType'],
 * }, function (err, state) {
 * 	let chartType = state['chartType'];
 * 	let myChartLayout = state['myChartLayout'];
 * });
 * ```
 * @param {object} params
 * @param {string} params.field Field to retrieve.
 * @param {Array.<string>} params.fields Fields to retrieve.
 * @param {string} params.windowName Window whose component state you are retrieving. If null, defaults to the calling window.
 * @param {function} cb The callback to be invoked after the method completes successfully.
 */
export const getComponentState = async (params, cb) => new Promise(async (resolve) => {
    if (!params) {
        params = {};
    }
    if (params.fields && !Array.isArray(params.fields)) {
        params.fields = [params.fields];
    }
    const elementFinsembleWindow = await getElementFinsembleWindow(params);
    elementFinsembleWindow.getComponentState(params, (err, data) => {
        cb === null || cb === void 0 ? void 0 : cb(err, data);
        resolve({ err, data });
    });
});
/**
 * @language javascript, java, dotnet
 * Given a field, this function sets and persists app state.
 *
 * Here is how to save the chart layout when it changes.
 * ```javascript
 * let s = stx.exportLayout(true);
 * //saving layout'
 * FSBL.Clients.WindowClient.setComponentState({ field: 'myChartLayout', value: s });
 * FSBL.Clients.WindowClient.setComponentState({ fields: [
 * 	{field:'myChartLayout', value: s },
 * 	{field:'chartType', value: 'mountain'}
 * ]});
 * ```
 * @param {object} params Object of data to be saved
 * @param {string} params.field The key name of the field to be saved. Required if not using `fields`.
 * @param {Array.<object>} params.fields An array of objects with `field` and `value` keys to be saved.
 * @param {string} params.windowName Name of the component whose state you are setting. Defaults to the calling window.
 * @param {any} params.value Value of the data being saved. Required if not using `fields`.
 * @param {function} cb The callback to be invoked after the method completes successfully.
 */
export const setComponentState = async (params, cb) => new Promise(async (resolve) => {
    const elementFinsembleWindow = await getElementFinsembleWindow(params);
    elementFinsembleWindow.setComponentState(params, (err) => {
        cb === null || cb === void 0 ? void 0 : cb(err);
        resolve({ err });
    });
});
/**
 * @language javascript, java, dotnet
 * Given a field, this function removes it from app state.
 *
 * The example below shows how we would remove our chart layout when it no longer needed.
 * ```javascript
 * // remove unused state value
 * FSBL.Clients.WindowClient.removeComponentState({ field: 'myChartLayout'});
 * FSBL.Clients.WindowClient.removeComponentState({ fields: [{field:'myChartLayout'}, {field:'chartType'}]});
 * ```
 * @param {object} params Object of data to be removed
 * @param {string} params.field The key name of the field to be saved. Required if not using `fields`.
 * @param {Array.<object>} params.fields An array of objects with `field` keys to be removed.
 * @param {string} params.windowName The name of the window to remove component state from
 * @param {function} cb The callback to be invoked after the method completes successfully.
 */
export const removeComponentState = async (params, cb) => new Promise(async (resolve) => {
    const elementFinsembleWindow = await getElementFinsembleWindow(params);
    elementFinsembleWindow.removeComponentState(params, (err) => {
        cb === null || cb === void 0 ? void 0 : cb(err);
        resolve({ err });
    });
});
/**
 * @language javascript
 * Gets the window name of current window. The code that manages window movement will not see a child window if it's part of a stacked window. This function will return the window name that the Window Service cares about for window movement.
 * @deprecated
 *
 * Gets the window name of current window or the parent, if tabbed. The code that manages window movement will not see a child window if it's part of a stacked window. This function will return the window name that the Window Service cares about for window movement.
 */
export const getWindowNameForDocking = () => {
    Logger.deprecated("WindowClient.getWindowNameForDocking is deprecated and will be removed");
    return deprecatedGetWindowNameForDocking(FEAGlobals.finsembleWindow);
};
/**
 * @language javascript
 * @deprecated
 * Forms a group with any window that is touching the border of this window.
 */
export const formGroup = () => {
    Logger.system.deprecated("WindowClient.formGroup() is deprecated.");
    FEAGlobals.finsembleWindow.formGroup();
};
/**
 * Adds finsembleWindow listeners for the command channel to the WindowTitleBar.
 *
 * These listeners are auto-cleaning when a window closes, so there is no need to manually close
 * them during destruction.
 */
const addListeners = () => {
    Logger.deprecated("Do not call WindowClient.addListeners() directly");
};
/**
 * @language javascript
 * @deprecated
 * Ejects the window from the docking group
 */
export const ejectFromGroup = () => {
    Logger.system.deprecated("WindowClient.ejectFromGroup() is deprecated.");
    FEAGlobals.finsembleWindow.ejectFromGroup();
};
/**
 * @language javascript, java, dotnet
 * This method overrides the app title that displays in the app's title bar or tab. This will take precedence over
 * the document.title or title that is set in the app's config. This will however be overridden by an user edited title.
 * @param title Window title.
 */
const setWindowTitle = (title) => {
    const store = getRemoteStoreAsSingleton({
        singletonName: "WindowClient::setWindowTitle",
        server: "@@finsemble/remoteRedux/WindowServiceStore",
        slice: "windowTitleBar",
        emptyStore,
        dispatchOnly: true,
    });
    store.dispatch(actions.setAPITitle({
        title,
    }));
};
/**
 * @language javascript, java, dotnet
 * Retrieves data that was set with <a href="/docs/reference/typedocs/modules/LauncherClient#spawn">LauncherClient.spawn</a>.
 * @returns The spawnData that was passed to calls to LauncherClient.spawn, or an empty object.
 */
export const getSpawnData = () => {
    var _a, _b, _c;
    const controller = getControllerInstance();
    return (_c = (_b = (_a = controller.options) === null || _a === void 0 ? void 0 : _a.customData) === null || _b === void 0 ? void 0 : _b.spawnData) !== null && _c !== void 0 ? _c : {};
};
/**
 * @language javascript, java, dotnet
 * @deprecated Use `FSBL.System.Window.getCurrent()`
 *
 * Returns a reference to the current FEAWindow for the component.
 * @returns {finWindow}
 */
export const getCurrentWindow = () => {
    // getCurrentWindow() is still being used by e2e tests and the zoom.js preload. Don't change this to
    // Logger.deprecated() until those systems are refactored to use FSBL.System.Window.
    Logger.system.deprecated("WindowClient.getCurrentWindow() is no longer supported and will likely go away in the future. Use FSBL.System.Window.getCurrent() instead.");
    Logger.log("WindowClient.getCurrentWindow() is deprecated and will be removed in a future release.");
    return System.Window.getCurrent();
};
/**
 * For the DOM element that has been passed in, this function returns a bounding box that is relative
 * to the virtual monitor space. That is, it returns the position of the DOM element on the desktop.
 * @param {HTMLElement|string} element A selector or HTMLElement
 */
const getDesktopBoundingBox = async (element) => {
    Logger.deprecated("WindowClient.getDesktopBoundingBox() is deprecated and will be removed in a future release.");
    return getDesktopBoundingBoxFromUtil(element);
};
/**
 * @deprecated This code will be moved into finsemble-ui
 */
const isPointInBox = (point, box) => {
    Logger.deprecated("WindowClient.isPointInBox() is deprecated and will be removed in a future release.");
    return isPointInBoxFromUtil(point, box);
};
/**
 * Returns (via callback) true if the mouse is currently located (hovering) over the requested element.
 * @param {HTMLElement|string} element The element, or a selector, to check
 * @param {function} cb A function that returns a boolean
 */
const isMouseOverDOMElement = (element, cb) => {
    Logger.deprecated("WindowClient.isMouseOverDOMElement() is deprecated and will be removed in a future release.");
    return isMouseOverDOMElementFromUtil(element, cb);
};
/**
 * @language javascript, java, dotnet
 * Returns the window identifier for the current component.
 * @returns {WindowIdentifier}
 */
export const getWindowIdentifier = () => {
    var _a, _b, _c, _d, _e, _f, _g, _h;
    const controller = getControllerInstance();
    return {
        windowName: (_b = (_a = FEAGlobals.finsembleWindow) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : window.name,
        uuid: (_d = (_c = FEAGlobals.finsembleWindow) === null || _c === void 0 ? void 0 : _c.uuid) !== null && _d !== void 0 ? _d : undefined,
        componentType: (_h = (_g = (_f = (_e = controller.options) === null || _e === void 0 ? void 0 : _e.customData) === null || _f === void 0 ? void 0 : _f.component) === null || _g === void 0 ? void 0 : _g.type) !== null && _h !== void 0 ? _h : null,
    };
};
/**
 * @deprecated
 * Highlights the window as active by creating a border around the window.
 *
 * @param {boolean} active  Set to false to turn off activity
 */
const setActive = (active) => {
    Logger.deprecated("WindowClient.setActive is deprecated and will be removed");
    deprecatedSetActive(active);
};
/**
 * @language javascript, java, dotnet
 * Returns the object defining bounds for the current window including the position of the left and right edges measured in pixels from the left edge of the monitor, the top and bottom edges measured in pixels from the top edge, and the width and height of the component in pixels.
 * Please note that this method differs from the right and bottom coordinates passed to LauncherClient.spawn(); those are measured from the right and bottom edges of the screen.
 * @param {StandardCallback} cb The callback to be invoked after the method completes successfully.
 */
export const getBounds = (cb) => FEAGlobals.finsembleWindow.getBounds(cb);
/**
 * @language javascript
 * @deprecated
 * Defines areas of the window that will be displayed and clickable. All other areas of the window will be transparent.
 * Can be used to create click-through areas of a window.
 *
 * @param params Optional. Takes an array of rectangle Objects for the areas of the window that will be displayed and clickable.
 * Passing in an empty array or omitting this parameter will cause the full area of the window to be displayed and clickable.
 * A rectangle is defined as: {
 * 	x: x coordinate for the origin of the rectangle (integer)
 *  y: x coordinate for the origin of the rectangle (integer)
 *  width: width of the rectangle (integer)
 *  height: height of the rectangle (integer)
 * }
 * @param callback: Function = Function.prototype
 */
export const setShape = (params, callback = Function.prototype) => {
    Logger.system.deprecated("WindowClient.setShape() is deprecated.");
    FEAGlobals.finsembleWindow.setShape(params, callback);
};
/**
 * @language javascript
 * This is used by the Finsemble window title bar when a tab is dragged for tiling or tabbing.
 * @param {*} params - <code>params.windowIdentifier</code> is required.
 * @param {WindowIdentifier} params.windowIdentifier The Finsemble identifier for the target window.
 * @param {*} cb The callback to be invoked after the method completes successfully.
 * @deprecated This code will be moved into finsemble-ui
 */
export const startTilingOrTabbing = (params, cb) => {
    Logger.deprecated("WindowClient.startTilingOrTabbing is deprecated and will be removed");
    RouterClient.transmit("DockingService.startTilingOrTabbing", params);
    cb === null || cb === void 0 ? void 0 : cb();
};
/**
 * @language javascript
 * @deprecated
 * Begin programmatically moving the window; the first parameter is a mouse event. Until `stopMovingWindow` is invoked, the window will follow the user's mouse. This should be invoked inside of a `mouseDown` event handler.
 */
export const startMovingWindow = (event) => {
    const currentWindow = System.Window.getCurrent();
    currentWindow.startMovingWindow(event);
};
/**
 * @language javascript
 * @deprecated
 * Stops moving a window that was set in motion via `startMovingWindow`.
 */
export const stopMovingWindow = () => {
    const currentWindow = System.Window.getCurrent();
    currentWindow.stopMovingWindow();
};
/**
 * @language javascript
 * This is used to cancel a tabbing or tiling operation.
 *
 * @param {object} params
 * @param {WindowIdentifier} params.windowIdentifier The Finsemble identifier for the window.
 * @param {Function} cb - The callback to be invoked after the method completes successfully.
 * @deprecated This code will be moved into finsemble-ui
 */
export const cancelTilingOrTabbing = (params, cb) => {
    Logger.deprecated("WindowClient.cancelTilingOrTabbing is deprecated and will be removed");
    console.debug("CancelTilingOrTabbing");
    RouterClient.transmit("DockingService.cancelTilingOrTabbing", params);
    cb === null || cb === void 0 ? void 0 : cb();
};
/**
 * @language javascript, java
 * This function is used by the Finsemble window title bar to end tiling or tabbing.
 * @param {*} params
 * @param {object} params.mousePosition Where the pointer is on the screen
 * @param {number} params.mousePosition.x X position of the pointer
 * @param {number} params.mousePosition.y Y position of the pointer
 * @param {boolean} params.allowDropOnSelf Determines whether a tab can be dropped on the window where the drag originated.
 * @param {*} cb - The callback to be invoked after the method completes successfully.
 * @deprecated This code will be moved into finsemble-ui
 */
export const stopTilingOrTabbing = (params, cb) => {
    Logger.deprecated("WindowClient.stopTilingOrTabbing is deprecated and will be removed");
    // We both transmit and query because no stack operation should happen until this is done and there are a lot of listeners around.
    const transmitAndQueryStop = () => {
        RouterClient.query("DockingService.stopTilingOrTabbing", params, () => {
            cb === null || cb === void 0 ? void 0 : cb();
        });
        RouterClient.transmit("DockingService.stopTilingOrTabbing", params);
    };
    // Get the mouse position if not passed through for transmit to the router,
    // If allowDropOnSelf is true, it came from a tab/window drop event. Run the callback.
    if (!params.mousePosition) {
        System.getMousePosition((err, position) => {
            params.mousePosition = position;
            transmitAndQueryStop();
            if (!params.allowDropOnSelf)
                cb === null || cb === void 0 ? void 0 : cb();
        });
        return;
    }
    transmitAndQueryStop();
    if (!params.allowDropOnSelf)
        cb === null || cb === void 0 ? void 0 : cb();
};
/**
 *
 */
const getMonitorInfo = async (params = {}, cb) => {
    Logger.deprecated("WindowClient.getMonitorInfo() is deprecated and will be removed. Please use LauncherClient.getMonitorInfo()");
    return getWhichMonitorClientSide(RouterClient, params, cb);
};
/**
 * @language javascript, java, dotnet
 * Moves the window so that it's centered above the user's mouse.
 */
export const showAtMousePosition = () => {
    RouterClient.transmit("DockingService.showAtMousePosition", getWindowIdentifier());
};
/**
 * @language javascript
 * Resize the window to fit the contents of the window's DOM, with optional padding.
 *
 * @param [params] optional parameters
 * @param [params.padding] allow for padding around to DOM contents
 * @param {number} [params.padding.height] extra pixels to add to the total height of the window. Default is 0
 * @param {number} [params.padding.width] extra pixels to add to the total width of the window. Default is 0
 * @param {number} [params.maxHeight] the maximum height to size the window to
 * @param {number} [params.maxWidth] the maximum width to size the window to
 * @param [cb] The callback to be invoked after the method completes successfully.
 */
export const fitToDOM = async (params, cb) => {
    var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
    if (typeof params === "function") {
        cb = params;
        params = null;
    }
    const paddingHeight = (_b = (_a = params === null || params === void 0 ? void 0 : params.padding) === null || _a === void 0 ? void 0 : _a.height) !== null && _b !== void 0 ? _b : 0;
    const paddingWidth = (_d = (_c = params === null || params === void 0 ? void 0 : params.padding) === null || _c === void 0 ? void 0 : _c.width) !== null && _d !== void 0 ? _d : 0;
    const { data: bounds } = await FEAGlobals.finsembleWindow.getBounds();
    if (!bounds)
        return;
    /*
    // Injected title bars monkey with the body height by setting a calc() in the css
    // We have to remove this to get the necessary calculations to fit to the DOM
    if(document.body.style.height?.includes("calc"))
        document.body.style.height = "auto";
        */
    // The window will never be set larger than the monitor
    const { data: monitorInfo } = await getWhichMonitorClientSide(RouterClient, {});
    const monitorHeight = (_f = (_e = monitorInfo === null || monitorInfo === void 0 ? void 0 : monitorInfo.availableRect) === null || _e === void 0 ? void 0 : _e.height) !== null && _f !== void 0 ? _f : Infinity;
    const monitorWidth = (_h = (_g = monitorInfo === null || monitorInfo === void 0 ? void 0 : monitorInfo.availableRect) === null || _g === void 0 ? void 0 : _g.width) !== null && _h !== void 0 ? _h : Infinity;
    // The titlebar takes up additional height when we're in a browserview.
    // This will calculate that extra height so that we can add it to the overall calculation
    const titlebarHeight = bounds.height - window.innerHeight;
    const verticalScrollbarWidth = window.innerWidth - document.getElementsByTagName("html")[0].clientWidth;
    const horizontalScrollbarHeight = window.innerHeight - document.getElementsByTagName("html")[0].clientHeight;
    // When the horizontal scrollbar is present we need one extra pixel of height to eliminate the vertical scrollbar
    const maybeExtraPixel = horizontalScrollbarHeight ? 1 : 0;
    // offsetHeight is the height of the content, including a horizontal scrollbar if it exists
    const calculatedHeight = document.documentElement.offsetHeight + paddingHeight + titlebarHeight + maybeExtraPixel;
    // We add the verticalScrollbarWidth to prevent the window width from shrinking when we eliminate a vertical
    // scrollbar. We use scrollWidth to ensure that the width expands to cover any hidden horizontal content.
    const calculatedWidth = document.documentElement.scrollWidth + paddingWidth + verticalScrollbarWidth;
    // The end result is the lesser of: calculated size, requested maximum size, and monitor size
    const newHeight = Math.min(calculatedHeight, (_j = params === null || params === void 0 ? void 0 : params.maxHeight) !== null && _j !== void 0 ? _j : calculatedHeight, monitorHeight);
    const newWidth = Math.min(calculatedWidth, (_k = params === null || params === void 0 ? void 0 : params.maxWidth) !== null && _k !== void 0 ? _k : calculatedWidth, monitorWidth);
    Logger.system.debug("WindowClient.FitToDOM:newHeight:newWidth", newHeight, newWidth, params);
    if (bounds.width != newWidth || bounds.height != newHeight) {
        await FEAGlobals.finsembleWindow.setBounds({
            bounds: {
                left: bounds.left,
                top: bounds.top,
                width: newWidth,
                height: newHeight,
            },
        });
    }
    cb === null || cb === void 0 ? void 0 : cb();
};
/**
 * @language javascript, dotnet
 * Forms a tab collection from a list of _existing_ windows. (See [LauncherClient.spawnTabCollection()](./LauncherClient#spawnTabCollection) to form a tab
 * collection from non-existing windows.)
 *
 * ```javascript
 * await FSBL.Clients.WindowClient.createTabCollection({
 * 	windowNames: ["MyApp-3443-fdf-343-fdfdf","MyOtherApp-dfdf-sdsd-dfdf-sdsd"],
 * 	promotedTab: "MyOtherApp-dfdf-sdsd-dfdf-sdsd"
 * })
 * ```
 * @param __namedParameters.windowNames - An array of window names to put in the collection. The tabs will retain the ordering of this array.
 * @param __namedParameters.promotedTab - The name of the tab to be promoted. If not set then the first window will be promoted.
 */
export const createTabCollection = async ({ windowNames, promotedTab, }) => {
    const store = getRemoteStoreAsSingleton({
        singletonName: "WindowClient::tabCollection",
        server: "@@finsemble/remoteRedux/WindowServiceStore",
        slice: "api",
        emptyStore,
        dispatchOnly: true,
    });
    store.dispatch(actions.createTabCollection({
        windowNames,
        promotedWindowName: promotedTab,
    }));
};
/**
 * @language javascript, dotnet
 * Adds one or more windows to an existing tab collection.
 *
 * ```javascript
 * await FSBL.Clients.WindowClient.addToTabCollection({
 * 	tabCollectionId: ["StackedWindow-sdsd-343-dsds"],
 * 	windowNames: ["MyApp-3443-fdf-343-fdfdf","MyOtherApp-dfdf-sdsd-dfdf-sdsd"],
 * 	position: 2,
 * 	promotedTab: "MyOtherApp-dfdf-sdsd-dfdf-sdsd"
 * })
 * ```
 * @param __namedParameters.windowNames - An array of window names to be added to the collection.
 * @param __namedParameters.tabCollectionId - ID of the tabCollection to join.
 * @param __namedParameters.position - Specifies where in the collection to add the new tabs. If not set then they will be appended to the end of the collection.
 * @param __namedParameters.promotedTab - Tab to be promoted. If not set then the promoted tab will not be changed.
 */
export const addToTabCollection = async ({ windowNames, tabCollectionId, position, promotedTab, }) => {
    const store = getRemoteStoreAsSingleton({
        singletonName: "WindowClient::tabCollection",
        server: "@@finsemble/remoteRedux/WindowServiceStore",
        slice: "api",
        emptyStore,
        dispatchOnly: true,
    });
    store.dispatch(actions.addTabsToTabCollection({
        windowNames,
        tabCollectionId,
        position,
        promotedWindowName: promotedTab,
    }));
};
/**
 * @language javascript, dotnet
 * Removes one or more tabs from their tab collection(s). The tab collection is identified automatically.
 * Tab collections with fewer than two tabs are removed from the system. If the tab collection is maximized then
 * windows that are removed will be restored to their previous unmaximized position and size.
 *
 * ```javascript
 * await FSBL.Clients.WindowClient.removeFromTabCollection({
 * 	windowNames: ["MyApp-3443-fdf-343-fdfdf","MyOtherApp-dfdf-sdsd-dfdf-sdsd"],
 * })
 * ```
 * @param __namedParameters.windowNames - The array of window names to be removed.
 * @param __namedParameters.visibility - An optional parameter to indicate whether the removed windows should be made visible after they are removed.
 */
export const removeFromTabCollection = async ({ windowNames, visibility, }) => {
    const store = getRemoteStoreAsSingleton({
        singletonName: "WindowClient::tabCollection",
        server: "@@finsemble/remoteRedux/WindowServiceStore",
        slice: "api",
        emptyStore,
        dispatchOnly: true,
    });
    store.dispatch(actions.removeTabsFromTabCollection({
        windowNames,
        visibility: visibility !== null && visibility !== void 0 ? visibility : true,
    }));
};
/**
 * @language javascript, dotnet
 * Changes the visible tab in a tab collection. (The tab collection is identified automatically.)
 *
 * ```javascript
 * await FSBL.Clients.WindowClient.promoteTab("MyApp-3443-fdf-343-fdfdf");
 * ```
 * @param windowName - The name of the tab to be promoted.
 */
export const promoteTab = async (windowName) => {
    const store = getRemoteStoreAsSingleton({
        singletonName: "WindowClient::tabCollection",
        server: "@@finsemble/remoteRedux/WindowServiceStore",
        slice: "windowTitleBar",
        emptyStore,
        dispatchOnly: true,
    });
    store.dispatch(actions.promoteTab({
        targetWindowName: windowName,
    }));
};
/**
 * @language javascript, dotnet
 * Gets the name of the promoted tab for a given tab collection.
 *
 * ```javascript
 * const {err, data: windowName } = await FSBL.Clients.WindowClient.getPromotedTab({
 * 	tabCollectionId: ["StackedWindow-dfdf-sdsd-dfdfdf-343434"]
 * });
 * if(windowName) console.log(`The promoted window is ${windowName}`)
 * ```
 * @param __namedParameters.tabCollectionId - ID of the tab collection.
 * @param cb - Optional callback to be invoked after the method completes successfully.
 * @return - Resolves to a tuple containing an error message and the name of the promoted tab in the collection.
 */
export const getPromotedTab = async ({ tabCollectionId }, cb) => {
    var _a, _b, _c;
    const state = (await getRemoteState({
        server: "@@finsemble/remoteRedux/WindowServiceStore",
        slice: "windowTitleBar",
    }));
    const promotedTab = (_c = (_b = (_a = state === null || state === void 0 ? void 0 : state.windowTitleBar) === null || _a === void 0 ? void 0 : _a.tabCollections) === null || _b === void 0 ? void 0 : _b[tabCollectionId]) === null || _c === void 0 ? void 0 : _c.promotedWindowName;
    if (!promotedTab) {
        const err = `No promoted tab found for tab collection ${tabCollectionId}`;
        cb === null || cb === void 0 ? void 0 : cb(err);
        return { err };
    }
    else {
        cb === null || cb === void 0 ? void 0 : cb(null, promotedTab);
        return { err: null, data: promotedTab };
    }
};
/**
 * @language javascript, dotnet
 * Gets the tabCollectionId for a given window, if it is a member of a tab collection.
 *
 * ```javascript
 * const {err, data } = await FSBL.Clients.WindowClient.getTabCollectionForWindow({
 * 	windowName: "MyApp-dfdf-sdsd-dfdfdf-343434"
 * });
 * if(data) console.log(`The tab collection ${data.id} contains these windows: ${data.windows}`);
 * ```
 * @param __namedParameters.windowName - The name of a window that should be in a tab collection.
 * @param cb - Optional callback to be invoked after the method completes.
 * @return - Resolves to a tuple with error message and object containing the tabCollectionId and a list of the windows in that collection.
 * An error will result if the window is not a member of any tab collection.
 */
export const getTabCollectionForWindow = async ({ windowName }, cb) => {
    var _a, _b, _c, _d, _e, _f, _g;
    const state = (await getRemoteState({
        server: "@@finsemble/remoteRedux/WindowServiceStore",
        slice: "windowTitleBar",
    }));
    const id = (_c = (_b = (_a = state === null || state === void 0 ? void 0 : state.windowTitleBar) === null || _a === void 0 ? void 0 : _a.windows) === null || _b === void 0 ? void 0 : _b[windowName]) === null || _c === void 0 ? void 0 : _c.tabCollectionId;
    if (!id) {
        const err = id ? null : `No tab collection found for window ${windowName}`;
        cb === null || cb === void 0 ? void 0 : cb(err);
        return { err };
    }
    const data = {
        id,
        windows: (_e = (_d = state === null || state === void 0 ? void 0 : state.windowTitleBar) === null || _d === void 0 ? void 0 : _d.tabCollections[id]) === null || _e === void 0 ? void 0 : _e.tabs,
        promotedWindowName: (_g = (_f = state === null || state === void 0 ? void 0 : state.windowTitleBar) === null || _f === void 0 ? void 0 : _f.tabCollections[id]) === null || _g === void 0 ? void 0 : _g.promotedWindowName,
    };
    cb === null || cb === void 0 ? void 0 : cb(null, data);
    return { err: null, data };
};
/**
 * @language javascript, dotnet
 * Gets names of all the windows that are part of a tab collection.
 *
 * ```javascript
 * const {err, data } = await FSBL.Clients.WindowClient.getTabCollection({
 * 	id: "StackedWindow-dfdf-sdsd-dfdfdf-343434"
 * });
 * if(data) console.log(`The tab collection contains these windows: ${data.windows}`);
 * ```
 * @param __namedParameters.collectionId - The name of the tab collection.
 * @param cb - Optional callback to be invoked after the method completes.
 * @return - Resolves to a tuple with error message and object containing the list of the windows in that collection and the currently promoted window.
 */
export const getTabCollection = async ({ id }, cb) => {
    const state = (await getRemoteState({
        server: "@@finsemble/remoteRedux/WindowServiceStore",
        slice: "windowTitleBar",
    }));
    const collection = state.windowTitleBar.tabCollections[id];
    if (!collection) {
        const err = `No tab collection "${id}" found.`;
        cb === null || cb === void 0 ? void 0 : cb(err);
        return { err };
    }
    const data = {
        windows: collection.tabs,
        promotedWindowName: collection.promotedWindowName,
    };
    cb === null || cb === void 0 ? void 0 : cb(null, data);
    return { err: null, data };
};
/**
 * @ignore
 *
 * Getters and setters are used to map `options`,`title`,`windowGroups` and `commandChannel` to the WindowClientController
 * singleton. See its comments for a more complete discussion.
 */
export const WindowClient = {
    /**
     * @deprecated
     * @private
     */
    initialize: () => {
        Logger.deprecated("There is no need to call WindowClient.initialize().");
    },
    /**
     * For backward compatibility
     * @private
     * @deprecated
     */
    onReady: (cb) => {
        Logger.system.deprecated("It is no longer necessary to call WindowClient.onReady()");
        cb === null || cb === void 0 ? void 0 : cb();
    },
    addListeners,
    addToTabCollection,
    bringToFront,
    bringWindowToFront,
    cacheInitialBounds,
    cancelTilingOrTabbing,
    close,
    createTabCollection,
    ejectFromGroup,
    fitToDOM,
    formGroup,
    getBounds,
    getComponentState,
    getCurrentWindow,
    getDesktopBoundingBox,
    getMonitorInfo,
    getPromotedTab,
    getSpawnData,
    getTabCollection,
    getTabCollectionForWindow,
    getWindowTitle,
    getWindowBounds,
    getWindowGroups,
    getWindowNameForDocking,
    getWindowIdentifier,
    injectDOM,
    isMouseOverDOMElement,
    isPointInBox,
    maximize,
    minimize,
    promoteTab,
    removeComponentState,
    removeFromTabCollection,
    restore,
    retrieveMonitorDimensions,
    saveWindowBounds,
    setActive,
    setAlwaysOnTop,
    setComponentState,
    setShape,
    setTaskbarIconOverlay,
    setWindowTitle,
    showAtMousePosition,
    stopTilingOrTabbing,
    startMovingWindow,
    startTilingOrTabbing,
    stopMovingWindow,
    get options() {
        return getControllerInstance().options;
    },
    set options(newOptions) {
        getControllerInstance().options = newOptions;
    },
    get title() {
        return getControllerInstance().title;
    },
    set title(replacement) {
        getControllerInstance().title = replacement;
    },
    get windowGroups() {
        return getControllerInstance().windowGroups;
    },
    set windowGroups(replacement) {
        getControllerInstance().windowGroups = replacement;
    },
};
/**
 * @ignore
 */
export default WindowClient;
//# sourceMappingURL=windowClient.js.map