import { RouterClient } from "../clients/routerClient";
import { Logger } from "../clients/logger";
import * as util from "./util";
import PublicEventManager from "./events/PublicEventManager";
import { WINDOWSTATE } from "./constants";
import { System } from "./system";
import { FEAGlobals } from "./Globals";
import { actions, emptyStore } from "../platform/services/window/modules/actions";
import { getRemoteStoreAsSingleton } from "../common/redux/getRemoteStore";
import clone from "lodash/cloneDeep";
export class FinsembleView {
    constructor(params) {
        var _a;
        this.onLoadHandler = (event) => {
            if ((event === null || event === void 0 ? void 0 : event.viewId) === this.id) {
                this.subscriptions.forEach((cb) => cb === null || cb === void 0 ? void 0 : cb());
            }
        };
        this.win = params.win;
        this.id = params.id;
        this.subscriptions = [];
        this.isVisible = (_a = params.visible) !== null && _a !== void 0 ? _a : true;
    }
    async remove(cb = Function.prototype) {
        if (this.subscriptions.length > 0) {
            System.removeEventListener("browserView-content-loaded", this.onLoadHandler);
        }
        await this.win.removeBrowserView(this, cb);
    }
    async setBounds(bounds, cb = Function.prototype) {
        await this.win.setViewBounds({ view: this, bounds }, cb);
    }
    async bringToFront(cb = Function.prototype) {
        await this.win.bringViewToFront(this, cb);
    }
    async showView(cb = Function.prototype) {
        this.isVisible = true;
        await this.win.showBrowserView(this, cb);
    }
    async hideView(cb = Function.prototype) {
        this.isVisible = false;
        await this.win.hideBrowserView(this, cb);
    }
    onContentLoaded(cb = Function.prototype) {
        this.subscriptions.push(cb);
        if (this.subscriptions.length === 1) {
            System.addEventListener("browserView-content-loaded", this.onLoadHandler);
        }
    }
}
/**
 *
  <h2>Finsemble Window</h2>
  ----------

  This class provides access to some low level window management operations.

  This class is intended for internal-use only, so it may change without warning. Do not rely on this class.
  @constructor
 */
export class FinsembleWindow extends PublicEventManager {
    /**
     * @private
     * @param params
     */
    constructor(params) {
        super({
            name: params.name,
            sourceType: "Window",
        });
        this.types = {};
        this.wrapState = params.wrapState || "initializing";
        this.componentState = {};
        this.windowState = WINDOWSTATE.NORMAL;
        this.type = null;
        this.windowType = null;
        this.bounds = {};
        this.guid = `${Date.now()}_${Math.random()}`;
        this.WINDOWSTATE = WINDOWSTATE;
        this.windowOptions = {};
        // because we were doing this[i]=params[i] in the constructor jscrambler was creating a reference to "this" above _super_, causing everything to break
        this.doConstruction(params);
        this.componentKey = util.camelCase("activeWorkspace", this.name, this.name);
        this.windowKey = util.camelCase("activeWorkspace", this.name);
        FinsembleWindow.bindFunctions(this);
    }
    // allows backwards compatibility.
    /**
     * Internal use only - changes pre-3.5 event names to standardized, post-3.5 event names
     * @private
     * @param {string} event - name of the event
     */
    standardizeEventName(event) {
        // @todo - This needs some fiddling for typescript. (input type: string, return type: WindowEventName)
        switch (event) {
            // all of these should be deprecated in 3.5ish.
            case "bounds-set":
            case "stoppedMoving":
                return "bounds-change-end";
            case "startedMoving":
                return "bounds-change-start";
            case "bringToFront":
                return "broughtToFront";
            default:
                return event;
        }
    }
    /**
     * Add an event listener
     *
     * @param {WindowEventName} eventName - The event to be listened for
     * @param {Function} handler - The function that receives the notification
     * @returns {Function} - an unsubscriber
     * @example
     * const unsubscriber = finsembleWindow.addEventListener("maximized", (eventObject) => {
     *   console.log("The window was maximized. Passed event object:", eventObject);
     * });
     *
     * // To unsubscribe:
     * unsubscriber();
     */
    addEventListener(eventName, handler) {
        eventName = this.standardizeEventName(eventName);
        return super.addEventListener(eventName, handler);
    }
    /**
     * Deprecated - please use the unsubscriber returned by the addEventListener
     *
     * @param {string} eventName - The event to be listened for
     * @param {Function} handler - The handler function that was originally registered under addEventListener (must be a named function)
     * @example
     * const myFunc = (eventObj) => {console.log(eventObj)};
     * finsembleWindow.addEventListener("minimized", myFunc);
     * finsembleWindow.removeEventListener("minimized", myFunc);
     */
    removeEventListener(eventName, handler, logWarning = false) {
        // Should not be able to add closed listener on one's self because obviously those will not return back
        if (eventName === "closed" && FEAGlobals.finsembleWindow ? this.name === FEAGlobals.finsembleWindow.name : false) {
            return;
        }
        eventName = this.standardizeEventName(eventName);
        return super.removeEventListener(eventName, handler, logWarning);
    }
    /**
     * Internal use only - Returns the name of the window service channel for a given service or topic
     * @private
     * @param {string} channelTopic - the topic or service (eg, "close", "maximize")
     * @returns {string} the window service channel name, which can be used for router queries/listening
     */
    windowServiceChannelName(channelTopic) {
        return `WindowService-Request-${channelTopic}`;
    }
    /**
     * Internal use only - Returns the event channel name for a given topic
     * @private
     * @param {string} channelTopic - name of the event channel topic
     * @returns {string} the full event channel name
     */
    eventChannelName(channelTopic) {
        const name = this.name || this.windowName;
        return `WindowService-Event-${name}-${channelTopic}`;
    }
    /**
     * @private
     * @param params
     */
    doConstruction(params) {
        if (!params.setWindowType && !params.windowType) {
            // Default WindowType
            params.windowType = "WebWindow";
        }
        if (params.windowType) {
            // We need to make a specific kind of Window
            params.setWindowType = params.windowType;
            delete params.windowType; // Prevent infinite loop
            const BW = FinsembleWindow; // have to do this because we're mutating the class using static functions and all kinds of bad stuff. This tells the typescript compiler that the FinsembleWindow here is of type any -- basically don't worry about its type.
            return new BW(params);
        } // We are a specific kind of window
        if (params) {
            for (const i in params) {
                this[i] = params[i];
            }
        }
        if (!this.name)
            this.name = params.windowName;
        this.windowType = this.setWindowType;
    }
    /**
     * Internal Use Only - register BaseWindow extended classes by reference name
     *
     * @private
     * @param name - reference type
     * @param type - BaseWindow extended class
     * @example
     * finsembleWindow.registerType("WebWindow", WebWindow);
     */
    static registerType(name, type) {
        const BW = FinsembleWindow; // have to do this because we're mutating the class using static functions and all kinds of bad stuff. This tells the typescript compiler that the FinsembleWindow here is of type any -- basically don't worry about its type.
        if (!BW.types) {
            BW.types = {};
        }
        BW.types[name] = type;
    }
    /**
     * @private
     * This is used to bind all functions only in FinsembleWindow and not in the child wrappers to the wrappers. Without this binding, the value of "this" in the functions is wrong.
     * @param {} obj
     */
    static bindFunctions(obj) {
        obj.eventChannelName = obj.eventChannelName.bind(obj);
        obj.windowServiceChannelName = obj.windowServiceChannelName.bind(obj);
        obj.handleWrapRemoveRequest = obj.handleWrapRemoveRequest.bind(obj);
        obj.reload = obj.reload.bind(obj);
    }
    /**
     * Internal use only
     * If you want to get a FinsembleWindow instance (aka a Wrap, aka a WindowWrap), use `FSBL.FinsembleWindow.getInstance`
     * @private
     */
    static async createWrapFromUUIDAndName(name, params) {
        var _a;
        const { uuid, windowType } = params;
        if (params.waitForReady !== false) {
            try {
                await FinsembleWindow._windowReady(name); // wait to ensure the window is fully ready in the window service
                params.wrapState = "ready";
            }
            catch (err) {
                return { err };
            }
        }
        Logger.system.debug("WRAP LIFECYCLE:", name, "All information for wrap passed in, creating wrap locally");
        // Multiple requests for the same window could've come in at once. Right before we create this wrap, we should check that it hasn't been cached while we were waiting for _windowReady to resolve.
        const wrap = FinsembleWindow.cache[name];
        if (wrap) {
            Logger.system.debug("WRAP LIFECYCLE:", name, "Window found in the cache, returning without going to the Launcher");
            return { data: wrap };
        }
        const data = await FinsembleWindow._createWrap({
            ...params,
            windowIdentifier: (_a = params.windowIdentifier) !== null && _a !== void 0 ? _a : {
                uuid,
                name,
                windowName: name,
                windowType,
            },
        });
        return { data: data.wrap };
    }
    /**
     * Async wrap. Given a name/windowName, it will query the launcher for information required to wrap the window. Then it will return an object that can be operated on.
     * Also this creates a cache of all wrapped windows for performance. Our clients wrap the same window often and this was causing excessive messaging to the store and degrading performance.
     *
     * @param {*} params Need only name in most cases. For service and other cases where the window is not part of what the launcher considers active windows, name and uuid are required
     * @param {boolean} [params.waitForReady] If true, will async await for Finsemble to return ready before continuing to build the instance to return
     * @param {string} [params.name] - Name of the app (must include name or windowName)
     * @param {string} [params.windowName] - WindowName of the app (must include name or windowName)
     * @param [cb]
     * @example
     * const {wrap} = await FSBL.FinsembleWindow.getInstance({
     *   windowName: finsembleWindow.windowName
     * });
     *
     * // Sync alternative
     * FSBL.FinsembleWindow.getInstance({windowName: finsembleWindow.windowName}, (err, wrap) => {
     *   if(!err){
     *     // Do something with the wrap, aka the instance
     *   }
     * });
     */
    static getInstance(params, cb) {
        var _a;
        Logger.system.log(/*'bW9udGVyZXlzIGNvYXN0', */ `getInstance called with params:`, (params === null || params === void 0 ? void 0 : params.name) || params);
        // new async wrap
        const myName = System.Window.getCurrent().name;
        Logger.system.log(/*'bW9udGVyZXlzIGNvYXN0', */ `getInstance got name: `, myName);
        params = clone(params); // this function modifies params so clone to be safe
        const name = (_a = params === null || params === void 0 ? void 0 : params.windowName) !== null && _a !== void 0 ? _a : params === null || params === void 0 ? void 0 : params.name;
        return new Promise(async (resolve, reject) => {
            if (!name) {
                const error = `"name" is a required param`;
                cb === null || cb === void 0 ? void 0 : cb(error);
                reject(error);
                return;
            }
            params.windowName = name;
            // Return early if we already have the wrap cached.
            let wrap = FinsembleWindow.cache[name];
            if (wrap) {
                Logger.system.log(/*'bW9udGVyZXlzIGNvYXN0', */ "WRAP LIFECYCLE:", name, "Window found in the cache, returning without going to the Launcher");
                cb === null || cb === void 0 ? void 0 : cb(null, wrap);
                resolve({ wrap });
                return;
            }
            // If we already have all of the necessary information, just call createWrap.
            if (params.name) {
                const { err, data } = await FinsembleWindow.createWrapFromUUIDAndName(name, params);
                if (err || !data) {
                    cb === null || cb === void 0 ? void 0 : cb(err);
                    reject(err);
                    return;
                }
                cb === null || cb === void 0 ? void 0 : cb(null, data);
                resolve({ wrap: data });
                return;
            }
            // If we get here, then all we have is a window name
            // wait to ensure the window is fully ready in the window service
            if (params.waitForReady !== false) {
                try {
                    await FinsembleWindow._windowReady(name);
                    params.wrapState = "ready";
                }
                catch (err) {
                    cb === null || cb === void 0 ? void 0 : cb(err, null);
                    reject(err);
                    return;
                }
            }
            // Send a request to the launcher for more information so that we can construct the proper object.
            const { err, response } = await RouterClient.query("WindowService-Request-getWindowIdentifier", {
                windowName: name,
                requester: myName,
            });
            if (err) {
                Logger.system.error(err);
                cb === null || cb === void 0 ? void 0 : cb(err, null);
                reject(err);
                return;
            }
            // In a race, another thread may have already created the wrap while this thread was querying the window service
            // so check once more for prior existence before creating and caching a new wrap
            wrap = FinsembleWindow.cache[name];
            if (wrap) {
                Logger.system.log(/*'bW9udGVyZXlzIGNvYXN0', */ "WRAP LIFECYCLE:", params.name, "Information received from launcher, but wrap exists in cache. Returning cached wrap.");
                cb === null || cb === void 0 ? void 0 : cb(null, wrap);
                resolve({ wrap });
                return;
            }
            Logger.system.log(/*'bW9udGVyZXlzIGNvYXN0', */ "WRAP LIFECYCLE:", name, "Information received from launcher. Creating wrap.");
            const { identifier } = response.data;
            if (identifier.windowName) {
                identifier.name = identifier.windowName;
            }
            params.retrievedIdentifier = identifier;
            ({ wrap } = await FinsembleWindow._createWrap(params));
            if (response.data.descriptor)
                wrap.descriptor = response.data.descriptor;
            cb === null || cb === void 0 ? void 0 : cb(null, wrap);
            resolve({ wrap });
        });
    }
    /**
     * Creates a Finsemble WindowWrap
     * @param {*} params
     * @param {string} params.name The name of the window
     * @param {*} [params.retrievedIdentifier] Retrieved window identifier
     * @param {*} [params.windowIdentifier] The window identifier
     * @param {boolean} [param.setWindowType] If true, will set the window type
     * @private
     */
    static _createWrap(params) {
        return new Promise(async (resolve) => {
            const identifier = params.retrievedIdentifier || params.windowIdentifier;
            // WebApplication is essentially just an WebWindow in its own process. We can wrap it just like a window.
            if ((!params.setWindowType && !identifier.windowType) || identifier.windowType === "WebApplication") {
                // Default WindowType
                identifier.windowType = "WebWindow";
            }
            // Top level keeps important info (e.g., uuid, name, windowType).
            let paramsForWindow = { ...identifier };
            // Also pull in anything that was passed into the constructor (e.g., windowDescriptor, etc);
            paramsForWindow = Object.assign(paramsForWindow, params);
            paramsForWindow.setWindowType = paramsForWindow.windowType;
            delete paramsForWindow.windowType; // Prevent infinite loop
            Logger.system.log(/*'bW9udGVyZXlzIGNvYXN0', */ "WRAP LIFECYCLE: Placing wrap into the local cache.", identifier.windowName);
            let wrap = new FinsembleWindow(paramsForWindow);
            FinsembleWindow.cache[identifier.windowName] = wrap;
            wrap.windowType = identifier.windowType;
            wrap.identifier = identifier;
            /**
             * We can't use a normal "closed" event here because it would create a race condition between other "closed" event handlers registered
             * through this window. The function, handleWrapRemoveRequest, gets called as the result of receiving a "closed" event.
             * It then proceeds to destroy this FinsembleWindow, by shutting down all of the event listeners (via the parent class PublicEventManager).
             * But, if external code also listens for a "closed" event then it would be possible for the event listeners to be closed before that event
             * is triggered. This is due to the fact that FinsembleWindow opens a unique Router Responder for every addEventListener call (rather than listening only once per event and multiplexing
             * locally).
             *
             * The special closeFinal() function is guaranteed to run its handler after all other "closed" event handlers.
             */
            wrap.closeFinal(wrap.handleWrapRemoveRequest);
            wrap.addEventListener("maximized", async () => {
                wrap.windowState = WINDOWSTATE.MAXIMIZED;
                wrap.windowOptions.windowState = WINDOWSTATE.MAXIMIZED;
                const { data: maximizedBounds } = await wrap.getBounds();
                if (maximizedBounds) {
                    wrap.windowOptions.left = maximizedBounds.left;
                    wrap.windowOptions.top = maximizedBounds.top;
                    wrap.windowOptions.height = maximizedBounds.height;
                    wrap.windowOptions.width = maximizedBounds.width;
                    wrap.windowOptions.right = maximizedBounds.right;
                    wrap.windowOptions.bottom = maximizedBounds.bottom;
                    wrap.windowOptions.opacity = 1;
                    wrap.saveCompleteWindowState(wrap.windowOptions);
                }
            });
            wrap.addEventListener("minimized", () => {
                if (wrap.windowState === WINDOWSTATE.MAXIMIZED) {
                    wrap.windowState = WINDOWSTATE.MINIMIZED_WAS_MAXIMIZED;
                    wrap.windowOptions.windowState = WINDOWSTATE.MINIMIZED_WAS_MAXIMIZED;
                }
                else if (wrap.windowState === WINDOWSTATE.NORMAL) {
                    wrap.windowState = WINDOWSTATE.MINIMIZED_WAS_NORMAL;
                    wrap.windowOptions.windowState = WINDOWSTATE.MINIMIZED_WAS_NORMAL;
                }
                else {
                    Logger.system.warn("Invalid window state received listening to window minimize", wrap.windowState);
                }
            });
            wrap.addEventListener("restored", () => {
                wrap.windowState = WINDOWSTATE.NORMAL;
                wrap.windowOptions.windowState = WINDOWSTATE.NORMAL;
            });
            // Sometimes the wrapState of window wraps do not get updated to the "ready" state. This subscription
            // ensures that the wrapState is updated.
            const subscribeID = RouterClient.subscribe(`Finsemble.Component.State.${identifier.windowName}`, (err, res) => {
                if (err) {
                    Logger.system.error("Finsemble component state change error", err);
                }
                else {
                    const { state } = res.data;
                    wrap.wrapState = state;
                    RouterClient.unsubscribe(subscribeID);
                }
            });
            resolve({ wrap });
        });
    }
    /**
     * @private
     * @param name
     */
    static _getRemoveWrapChannel(name) {
        return `${System.Window.getCurrent().name}.removeWrap.${name}`;
    }
    /**
     * this routine handles the close event, but also called without event from FSBL
     * @private
     * @param event
     */
    async handleWrapRemoveRequest(event) {
        if (event)
            event.wait();
        Logger.system.debug("WRAP Destructor. Removing cached window", this.name, "in ", window.name);
        // wrap is the finsemble or stacked window. if the removeListeners function exists, we remove all listeners we added during the lifecycle of that window wrapper.
        if (this.removeListeners) {
            this.removeListeners();
        }
        // do not move this line of code. The order of execution is important.
        this.cleanupRouter();
        this.cleanup();
        if (this.name !== FEAGlobals.name && this.name) {
            delete FinsembleWindow.cache[this.name];
        }
        if (event)
            event.done();
    }
    /**
     * Called by FSBLDesktop on a window "unload". This removes all of the established wraps
     * and, importantly, cleans up their router listeners
     * @private
     */
    static closeAllWraps() {
        Object.values(FinsembleWindow.cache).forEach((wrap) => {
            wrap.handleWrapRemoveRequest();
        });
    }
    /**
     * @private
     */
    cleanupRouter() {
        const REMOVE_WRAP_CHANNEL = FinsembleWindow._getRemoveWrapChannel(this.name);
        RouterClient.removeResponder(REMOVE_WRAP_CHANNEL);
    }
    /**
     * Identify what to run when/if the component is ready.
     * If the component is already in a ready state when `onReady` is invoked,
     * the callback/promise will immediately resolve
     *
     * @param [callback]
     * @example
     * await finsembleWindow.onReady();
     * // Do stuff now that the component is ready
     *
     * // Sync alternative
     * finsembleWindow.onReady(() => {
     *   // Do stuff now that the component is ready
     * });
     */
    onReady(callback) {
        return new Promise((resolve) => {
            if (this.wrapState === "ready") {
                callback === null || callback === void 0 ? void 0 : callback();
                resolve();
                return;
            }
            this.addEventListener("ready", () => {
                callback === null || callback === void 0 ? void 0 : callback();
                resolve();
            });
        });
    }
    // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Common template for window-function requests to window service -- see public functions
    // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /**
     * @param {string} methodName method name (e.g. "minimize", "maximize")
     * @param {object} params
     * @param {function=} callback
     * @returns {StandardPromise<void>}
     * @private
     */
    queryWindowService(methodName, params, callback = Function.prototype) {
        if (typeof params === "function") {
            callback = params;
            params = {};
        }
        params = {
            ...params,
            windowIdentifier: this.identifier,
        };
        // if Logger debug is enable, then add call stack to query parameters for debugging -- shows where public window requests originated
        if (Logger.setting().system.Debug) {
            params.callstack = Logger.callStack(); // add callstack to query for debugging -- shows where public window requests originated
        }
        return new Promise(async (resolve) => {
            var _a;
            // All window functions except add event listener must wait until the window is ready.
            // And then we re-run this same method
            if (methodName !== "close" && this.wrapState !== "ready") {
                await this.onReady();
                this.wrapState = "ready";
                const data = await this.queryWindowService(methodName, params);
                callback(null, data);
                resolve(data);
                return;
            }
            Logger.system.debug("FinsembleWindow.queryWindowService", this.windowServiceChannelName(methodName), params);
            // breadcrumb, 2022-02-10: a lot of these responders are in windowPrimitivesEntryPoint.ts
            const { err, response } = await RouterClient.query(this.windowServiceChannelName(methodName), params);
            let responseData = (_a = response.data) !== null && _a !== void 0 ? _a : null;
            if (err) {
                Logger.system.debug(`WindowService.${methodName}: failed`, err);
                console.debug(`WindowService.${methodName}: failed`, err);
                // Views in components not in the workspace trigger this error spuriously
                if (methodName !== "getComponentState" && err !== "Not found") {
                    callback(err);
                    resolve({ err });
                    return;
                }
            }
            else {
                Logger.system.debug(`${this.windowServiceChannelName(methodName)} successful`, responseData);
                console.debug(`${this.windowServiceChannelName(methodName)} successful`, responseData);
            }
            callback(err, responseData);
            resolve(responseData);
        });
    }
    // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Core Window Functions: can be invoked by any service or component.  Most are sent to the WindowService to be executed.
    // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Core Public Window Functions: can be invoked by any service or component.  These are sent to the WindowService to be executed.
    // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /**
     * Minimizes the current window.
     * Use .restore() to reverse this action
     *
     * @param params This parameter is ignored.
     * @param [callback]
     * @example
     * const {err} = await finsembleWindow.minimize()
     *
     * // Sync alternative
     * finsembleWindow.minimize(null, (err) => {
     *   if(!err){
     *     // Do something
     *   }
     * })
     */
    minimize(params = null, cb) {
        return new Promise((resolve) => {
            this.queryWindowService("minimize", params, (err) => {
                cb === null || cb === void 0 ? void 0 : cb(err);
                resolve({ err });
            });
        });
    }
    /**
     * Maximizes the current window.
     * Use .restore() to reverse this action
     *
     * @param params This parameter is ignored.
     * @param [callback]
     * @example
     * const {err} = await finsembleWindow.maximize()
     *
     * // Sync alternative
     * finsembleWindow.maximize(null, (err) => {
     *   if(!err){
     *     // Do something
     *   }
     * })
     */
    maximize(params = null, cb) {
        return new Promise((resolve) => {
            this.getBounds((err1, bounds) => {
                if (err1 || !bounds) {
                    Logger.system.warn(`Error getting bounds, cached bounds will not be set: ${err1}`);
                }
                else {
                    this.updateOptions({
                        options: {
                            left: bounds.left,
                            top: bounds.top,
                            width: bounds.width,
                            height: bounds.height,
                        },
                    });
                }
                this.queryWindowService("maximize", params, (err) => {
                    cb === null || cb === void 0 ? void 0 : cb(err);
                    resolve({ err });
                });
            });
        });
    }
    /**
     * Restores a minimized or maximized component.
     * Note: restore does not show a hidden component.
     *
     * @param params This parameter is ignored.
     * @param [callback]
     * @example
     * const {err} = await finsembleWindow.restore()
     *
     * // Sync alternative
     * finsembleWindow.restore(null, (err) => {
     *   if(!err){
     *     // Do something
     *   }
     * })
     */
    restore(params = null, cb) {
        return new Promise((resolve) => {
            this.queryWindowService("restore", params, (err) => {
                cb === null || cb === void 0 ? void 0 : cb(err);
                resolve({ err });
            });
        });
    }
    /**
     * Blurs the current window
     *
     * @param params This parameter is ignored.
     * @param [callback]
     * @example
     * const {err} = await finsembleWindow.blur()
     *
     * // Sync alternative
     * finsembleWindow.blur(null, (err) => {
     *   if(!err){
     * 	   // Do something
     *   }
     * })
     */
    blur(params = null, cb) {
        return new Promise((resolve) => {
            this.queryWindowService("blur", params, (err) => {
                cb === null || cb === void 0 ? void 0 : cb(err);
                resolve({ err });
            });
        });
    }
    /**
     * Brings focus to the current window
     *
     * @param params This parameter is ignored.
     * @param [callback]
     * @example
     * const {err} = await finsembleWindow.focus()
     *
     * // Sync alternative
     * finsembleWindow.focus(null, (err) => {
     *   if(!err){
     * 	   // Do something
     *   }
     * })
     */
    focus(params = null, cb) {
        return new Promise((resolve) => {
            this.queryWindowService("focus", params, (err) => {
                cb === null || cb === void 0 ? void 0 : cb(err);
                resolve({ err });
            });
        });
    }
    /**
     * Brings the current window to front
     *
     * @param params This parameter is ignored.
     * @param [callback]
     * @example
     * const {err} = await finsembleWindow.bringToFront()
     *
     * // Sync alternative
     * finsembleWindow.bringToFront(null, (err) => {
     *   if(!err){
     * 	   // Do something
     *   }
     * })
     */
    bringToFront(params = null, cb) {
        return new Promise((resolve) => {
            this.queryWindowService("bringToFront", params, (err) => {
                cb === null || cb === void 0 ? void 0 : cb(err);
                resolve({ err });
            });
        });
    }
    /**
     * Sets the alwaysOnTop state for the window.
     * @param params Object representing the new alwaysOnTop state.
     * @param [callback] Callback identifying if there was an error
     * @example
     * const {err} = finsembleWindow.setAlwaysOnTop({alwaysOnTop: true});
     * // err should be null
     *
     * // Sync alternative
     * finsembleWindow.setAlwaysOnTop({alwaysOnTop: true}, (err) => {
     *   console.log(err); // null
     * })
     */
    setAlwaysOnTop(params = { alwaysOnTop: true }, cb) {
        return new Promise((resolve) => {
            this.queryWindowService("setAlwaysOnTop", params, (err) => {
                cb === null || cb === void 0 ? void 0 : cb(err);
                resolve({ err });
            });
        });
    }
    /**
     * Determine the state of the alwaysOnTop option for the window.
     * See also: setAlwaysOnTop, updateOptions
     *
     * @param params This parameter is ignored.
     * @param [callback]
     * @example
     * finsembleWindow.isAlwaysOnTop({}, (err, data) => {
     *   console.log(err); // null
     *   console.log(data); // true if always, false if minimized or hidden
     * })
     */
    isAlwaysOnTop(params = {}, callback) {
        this.queryWindowService("isAlwaysOnTop", params, callback);
    }
    /**
     * Determine if the current window is showing. A window is not showing when it is minimized or hidden.
     * See also: updateOptions
     *
     * @param params This parameter is ignored.
     * @param [callback]
     * @example
     * finsembleWindow.isShowing({}, (err, data) => {
     *   console.log(err); // null
     *   console.log(data); // true if showing, false if minimized or hidden
     * })
     */
    isShowing(params = {}, callback) {
        this.queryWindowService("isShowing", params, callback);
    }
    /**
     *  Experimental - There is an issue where resizing a window inside a click-through area causes flickering. This issue is present
     * in the electron base code. This implementation may be removed for an alternative solution.
     *
     * Instruct the window to ignore mouse events.
     * Optionally may allow mouse movement events to be forwarded while ignoring interaction events.
     *
     * Returns a promise that resolves to undefined.
     *
     * @param ignore Whether or not to have the window receive mouse events.
     * @param options An optional object with extra configuration parameters.
     * @param options.forward If true indicates mouse movement events are still triggered in the window.
     * @param callback Callback accepting two values: a (possible) error object and success message.
     * @returns {Promise<undefined>}
     * @private
     */
    setIgnoreMouseEvents(ignore, options, callback = Function.prototype) {
        const queryParams = {
            ignore: new Boolean(ignore).valueOf(),
            options: new Boolean(options).valueOf() ? options : { forward: false },
        };
        this.queryWindowService("setIgnoreMouseEvents", queryParams, callback);
    }
    /**
     * Use FSBL.Clients.WindowClient.setShape instead
     * (Doesn't work)
     * @private
     */
    setShape(params, callback = Function.prototype) {
        this.queryWindowService("setShape", params, callback);
    }
    /**
     * @private
     * @param params
     * @param callback
     * @returns
     */
    async addBrowserView(params, callback = Function.prototype) {
        const viewId = await this.queryWindowService("addBrowserView", params, callback);
        return new FinsembleView({ id: viewId, win: this, visible: params === null || params === void 0 ? void 0 : params.visible });
    }
    /**
     * @private
     * @param params
     * @param callback
     * @returns
     */
    async removeBrowserView(view, callback = Function.prototype) {
        await this.queryWindowService("removeBrowserView", { viewId: view.id }, callback);
    }
    /**
     * @private
     * @param params
     * @param callback
     * @returns
     */
    async bringViewToFront(view, callback = Function.prototype) {
        await this.queryWindowService("bringViewToFront", { viewId: view.id }, callback);
    }
    async showBrowserView(view, callback = Function.prototype) {
        await this.queryWindowService("showBrowserView", { viewId: view.id }, callback);
    }
    async hideBrowserView(view, callback = Function.prototype) {
        await this.queryWindowService("hideBrowserView", { viewId: view.id }, callback);
    }
    /**
     * @private
     * @param params
     * @param callback
     * @returns
     */
    async setViewBounds(params, callback = Function.prototype) {
        await this.queryWindowService("setViewBounds", { viewId: params.view.id, bounds: params.bounds }, callback);
    }
    /**
     * Set the bounding box for the current window.
     * See also: getBounds
     *
     * @param {Bounds} params.bounds - The new bounds for the window. Must provide left/top/height/width
     * @param [callback]
     * @example
     * await finsembleWindow.setBounds({bounds: {left: 0, top: 0, height: 600, width: 400}})
     */
    setBounds(params = { bounds: {} }, cb) {
        return new Promise((resolve) => {
            if (typeof params !== "function" && !params.bounds) {
                const oldParams = params;
                params = {
                    bounds: oldParams,
                };
            }
            this.queryWindowService("setBounds", params, (err) => {
                cb === null || cb === void 0 ? void 0 : cb(err);
                resolve({ err });
            });
        });
    }
    /**
     * Get the bounding box for the current window. The structure of the bounding box data looks like:
     * {top, left, bottom, right, height, width}
     *
     * See also: setBounds
     *
     * @params [cb] - Callback providing bounding data
     * @example
     * const {err, data} = await finsembleWindow.getBounds();
     * console.log("The width of the current window:", data.width);
     *
     * // Sync alternative
     * finsembleWindow.getBounds( (err, data) => {
     *   console.log("The width of the current window:", data.width);
     * })
     */
    getBounds(cb, backwardCompatibilityCB) {
        const promiseResolver = (resolve) => {
            // Old signature was getBounds({}, callback). New signature is getBounds(callback).
            const callback = typeof cb === "function" ? cb : backwardCompatibilityCB;
            this.queryWindowService("getBounds", {}, (err, bounds) => {
                callback === null || callback === void 0 ? void 0 : callback(err, bounds);
                resolve({ err, data: bounds });
            });
        };
        return new Promise(promiseResolver);
    }
    /**
     * Update options for the current window. One or more options can be set at a time.
     *
     * To confirm that the options were set, see also `getOptions`
     *
     * @param {WindowOptions} params - Options to be updated
     * @param [callback]
     *
     * @example
     * finsembleWindow.updateOptions({opacity: .5, alwaysOnTop: true}, () => {
     * 	// do something now that options have been updated
     * });
     */
    updateOptions(params, callback = Function.prototype) {
        // @todo: Supposedly, `title` should be supported, but I couldn't get that to update. Should investigate if it's supported, and update the jsdoc
        this.queryWindowService("updateOptions", params, callback);
    }
    /**
     * Hides the current window.
     * Use the `.show()` method to bring the current window back.
     *
     * @param {object} [params]
     * @param [callback]
     * @example
     * const {err} = await finsembleWindow.hide();
     *
     * // Sync alternative
     * finsembleWindow.hide({}, (err, data) => {
     *   console.log(err);	// null
     *   console.log(data); // {status: "success"}
     * })
     */
    hide(params = {}, cb) {
        return new Promise((resolve) => {
            this.queryWindowService("hide", params, (err, data) => {
                cb === null || cb === void 0 ? void 0 : cb(err, data);
                resolve({ err });
            });
        });
    }
    /**
     * Reloads the current window.
     *
     * @param params - This parameter is ignored.
     * @param callback - This parameter is ignored.
     * @example
     * finsembleWindow.reload()
     */
    reload(params = {}, callback = Function.prototype) {
        this.queryWindowService("reload", params, callback);
    }
    /**
     * Shows the current window. This will undo hide or minimize.
     *
     * @param {object} [params]
     * @param {boolean} [params.shouldMaximize] - when the window is shown, it should also be maximized
     * @param {boolean} [params.shouldRestore] -
     * @param {boolean} [params.saveState] -
     * @param [callback]
     * @example
     * const {err} = await finsembleWindow.show();
     * const {err} = await finsembleWindow.show({shouldMaximize: true});
     *
     * // Sync alternative
     * finsembleWindow.show({}, (err, data) => {
     *   console.log(err);	// null
     *   console.log(data); // {status: "success"}
     * })
     */
    show(params = {}, cb) {
        return new Promise((resolve) => {
            this.queryWindowService("show", params, (err, data) => {
                cb === null || cb === void 0 ? void 0 : cb(err, data);
                resolve({ err });
            });
        });
    }
    /**
     * Shows the current window at a particular coordinate location.
     * Note: this shows the window, but does not give it focus.
     *
     * @param params
     * @param {number} params.left
     * @param {number} params.top
     * @param callback
     * @example
     * finsembleWindow.showAt({left: 0, top: 0}, () => {
     *   // Do something
     * })
     */
    showAt(params = {}, callback = Function.prototype) {
        this.queryWindowService("showAt", params, callback);
    }
    /**
     * Close the current window
     *
     * @param params - This property is ignored
     * @param callback
     * @example
     * finsembleWindow.close()
     */
    close(params = {}, cb) {
        return new Promise((resolve) => {
            Logger.system.debug("WRAP CLOSE. Public close initiated for", this.name, params);
            this.queryWindowService("close", params, (err) => {
                Logger.system.debug("WRAP CLOSE. Public close initiated for", this.name);
                cb === null || cb === void 0 ? void 0 : cb(err);
                resolve({ err });
            });
        });
    }
    /**
     * While it *feels* like `animate` should animate something, it doesn't, and it never has.
     * Use `setBounds` instead.
     *
     * @private
     * @param params
     * @param callback
     */
    animate(params = {}, callback = Function.prototype) {
        this.queryWindowService("animate", params, callback);
    }
    /**
     * Register a window with docking. Use this if you don't want to use the full initialization function.
     * Undo this action with `.unRegisterWithDocking()`
     *
     * NOTE: The “params” object cannot be removed since assimilationWindowManager.ts invokes initializeWindow
     *       with params which are sent to registerWithDocking
     * @private
     * @param {Object} params - can be anything that is passed to docking for window registration.
     * @param {Function} cb
     */
    registerWithDocking(params = {}, cb) {
        this.onReady(() => {
            RouterClient.query("DockingService.registerWindow", params, cb);
        });
    }
    /**
     * Open a native file selection dialog on a window
     *
     * @param {Object} params - see https://www.electronjs.org/docs/api/dialog
     * @param {Function} cb
     * @example
     * finsembleWindow.showNativeOpenDialog({}, (err, [response]) => {
     *   if(!err && !response.canceled && !response.error){
     *     console.log("Files selected: ", response.filePaths)
     *   }
     * })
     *
     * finsembleWindow.showNativeOpenDialog(
     *   {
     *     buttonLabel: "My Custom Label",
     *     properties: ["multiSelections"]
     *   },
     *   (err, [response]) => {
     *     if(!err && !response.canceled && !response.error){
     *       console.log("Files selected: ", response.filePaths)
     *     }
     *   }
     * )
     */
    showNativeOpenDialog(params = {}, cb) {
        this.queryWindowService("showNativeOpenDialog", params, cb);
    }
    /**
     * Unregister a window with docking
     * @private
     */
    unRegisterWithDocking() {
        RouterClient.transmit("DockingService.deregisterWindow", {
            name: this.windowName,
        });
    }
    /**
     *This is if we want to handle the full register/ready state inside of the window
     register with docking
     send the message to launcher saying that component is ready
     * @private
     */
    initializeWindow({ manageWindowMovement, identifier }, cb = Function.prototype) {
        const publishComponentReady = () => {
            RouterClient.publish(`Finsemble.${this.windowName}.componentReady`, {
                // signal workspace and launcher service that component is ready
                name: this.windowName,
            });
            cb();
        };
        /** DH 12/13/2019 - While windows can opt out of grouping, etc. by setting
         * manageWindowMovement to false, we still need to perform the right initialization
         * handshake so Finsemble is aware of the window. Otherwise, Finsemble won't perform spawn
         * callbacks and the workspace won't close correctly.
         */
        if (manageWindowMovement) {
            this.registerWithDocking(identifier, publishComponentReady);
        }
        else {
            publishComponentReady();
        }
    }
    /**
     * Internal use only - publish the ready command
     * @private
     */
    wrapReady() {
        RouterClient.publish(`Finsemble.${this.windowName}.wrapReady`, {
            name: this.windowName,
            state: "open",
        });
    }
    /**
     * Set the opacity of the current window
     *
     * @param params - the new opacity for the window, in the form of `{opacity: ##}`
     * @param callback - callback when done
     * @example
     * finsembleWindow.setOpacity({opacity: .5}, (err) => {
     *   if(!err){
     *     // Do something now that opacity has successfully changed
     *   }
     * })
     */
    setOpacity(params, callback = Function.prototype) {
        this.queryWindowService("setOpacity", params, callback);
    }
    // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // Other BaseClass Function: These are common functions shared across derived classes
    // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    /**
     * Invoked to indicate an operation (e.g. dragging out of tab region) has started. This signals the Docking service to start tracking the mouse location and invoking tiling behavior as needed. Typically inherited (base function only).
     * @param {object} params for future use
     * @private
     * @example
     *	// dragging tab example using tracking and group
     * 	FinsembleWindow.startTabTileMonitoring();
     *	// if dragging tab is in a group, then remove it given tracking results will decide what to do with the window
     * 	FinsembleWindow.Group.getGroupID(this.identifier, function (err, tileGroupId) {
     * 		if (!err) { // if no error then must be in a tile group
     *			self.Group.removeWindow(this.identifier);
     *		}
     *	});
     */
    startTabTileMonitoring(params = {}) {
        Logger.system.debug("FinsembleWindow.startTabTileMonitoring", params);
        RouterClient.transmit("TabTile.startTabTile", { params });
    }
    /**
     * Invoked by client originating a dragStart that it has has ended. Typically inherited (base function only).
     * @param {object} params for future use
     * @param {function=} callback option callback that support overriding default behavior
     * @private
     * 	FinsembleWindow.stopTabTileMonitoring(params, function(err, results, defaultTabTileAction) {
     * 		// . . . custom code goes here . . .
     *		defaultTabTileAction(results); // now take default action or call your own function instead
     * 	});
     *
     */
    stopTabTileMonitoring(params = {}, callback = Function.prototype) {
        Logger.system.debug("FinsembleWindow.stopTabTileMonitoring", params);
        RouterClient.query("TabTile.stopTabTile", { params }, function (err, queryResponseMessage) {
            if (err) {
                Logger.system.warn("TabTile.stopTabTile: query failed", err);
            }
            else {
                Logger.system.debug("TabTile.stopTabTile results", queryResponseMessage.data);
            }
            const stopTabTileResults = queryResponseMessage.data;
            if (callback) {
                callback(err, stopTabTileResults, this.defaultStopTrackingAction);
            }
            else {
                this.defaultTabTileAction(stopTabTileResults);
            }
        });
    }
    /**
     * Defines default TabTile action for stopTabTileMonitoring.  May be overridden by client -- see example in stopTabTileMonitoring. Typically inherited (base function only).
     * @param {any} stopTabTileResults
     * @private
     */
    defaultTabTileAction(stopTabTileResults) {
        const self = this;
        Logger.system.debug("FinsembleWindow.defaultTabTileAction", stopTabTileResults);
        switch (stopTabTileResults.stoppedLocation) {
            case "OutsideWindow":
                // move window to drop location (since for now assuming only single-tabbed windows)
                break;
            case "TabSection":
                // WindowStack.addWindowToStack(callback) // for when we get to tabbing
                break;
            case "InsideWindow":
                if (stopTabTileResults.tileGroupId) {
                    // if dropped in an existing tile group (which might be the same it was dragging from)
                    self.Group.addWindow(this.identifier, stopTabTileResults.tileGroupId, stopTabTileResults.dropCoordinates);
                }
                else {
                    // if dropped in a separate window outside a tile group
                    self.Group.createGroup(function (newGroupId) {
                        // add dragging window to new tile group, but specify the dropped on window as the starting window in the tile group
                        self.Group.addWindow(this.identifier, newGroupId, stopTabTileResults.dropCoordinates, {
                            startingWindowIdentifier: stopTabTileResults.droppedOnWindowIdentifier,
                        });
                    });
                }
                break;
            default:
                Logger.system.error("stopTracking returned an unknown stoppedLocation result", stopTabTileResults);
        }
    }
    /**
     * Internal use only
     * @private
     * @param bounds
     */
    mergeBounds(bounds) {
        bounds.right = bounds.left + bounds.width;
        const newBounds = {
            left: bounds.left,
            right: bounds.right,
            width: bounds.width,
            top: bounds.top,
            bottom: bounds.top + bounds.height,
            height: bounds.height,
        };
        const defaultBounds = {
            defaultLeft: bounds.left,
            defaultWidth: bounds.width,
            defaultTop: bounds.top,
            defaultHeight: bounds.height,
        };
        Object.assign(this.windowOptions, newBounds);
        Object.assign(this.windowOptions, defaultBounds);
        this.windowOptions.bounds = newBounds;
    }
    /**
     * Make necessary visual and logistic changes when a window is about to be moved.
     * See also: stopMove
     *
     * @private
     * @param params - This is ignored
     */
    startMove(params = {}) {
        // @todo: Does this function actually do anything? I can't anything listening for this event
        Logger.system.debug("FinsembleWindow.startMove", params);
        params.windowIdentifier = this.identifier; // add this window's identifier
        RouterClient.transmit(this.eventChannelName("startedMoving"), {});
    }
    /**
     * Make necessary visual and logistic changes when a window is no longer being moved
     * See also: startMove
     *
     * @private
     * @param params - This is ignored
     */
    stopMove(params = {}) {
        // @todo: Does this function actually do anything? I can't anything listening for this event
        Logger.system.debug("FinsembleWindow.stopMove", params);
        params.windowIdentifier = this.identifier; // add this window's identifier
        RouterClient.transmit(this.eventChannelName("stoppedMoving"), {});
    }
    /**
     * Get Monitor for this window
     *
     * Example output for monitor data:
     * {
     *   name: "device1",
     *   availableRect: {width, height, top, bottom, left, right},
     *   bounds: {
     *     min: {x, y},
     *     max: {x, y},
     *   },
     *   top,
     *   bottom,
     *   left,
     *   right,
     * }
     *
     * @param {function} cb Callback
     * @example
     * finsembleWindow.getMonitor((monitorData) => {
     *   console.log(monitorData);
     * })
     */
    getMonitor(cb) {
        RouterClient.query("DockingService.getMonitorForWindow", { windowIdentifier: this.identifier }, (err, message) => message ? cb(message.data) : cb());
    }
    /**
     * @private
     * Alternative, use: `FSBL.Clients.WindowClient.getComponentState`
     */
    getComponentState(params, cb) {
        return new Promise((resolve) => {
            this.queryWindowService("getComponentState", params, (err, data) => {
                cb === null || cb === void 0 ? void 0 : cb(err, data);
                resolve({ err, data });
            });
        });
    }
    /**
     * @private
     */
    getWindowState(params, cb) {
        // @todo - Does this do anything? I couldn't get setWindowState/getWindowState to behave together,
        // and I can't find anywhere in the codebase that calls this function.
        this.queryWindowService("getWindowState", params, cb);
    }
    /**
     * @private
     * Internal use only
     * Alternative, use: `FSBL.Clients.WindowClient.setComponentState`
     */
    setComponentState(params, cb = () => { }) {
        this.queryWindowService("setComponentState", params, cb);
    }
    /**
     * @private
     * Internal use only
     * Alternative, use: `FSBL.Clients.WindowClient.removeComponentState`
     */
    removeComponentState(params, cb = () => { }) {
        this.queryWindowService("removeComponentState", params, cb);
    }
    /**
     * DEPRECATED
     * @private
     */
    setWindowState(params, cb = () => { }) {
        // @todo - Does this do anything? I couldn't get setWindowState/getWindowState to behave together,
        // and I can't find anywhere in the codebase that calls this function.
        this.queryWindowService("setWindowState", params, cb);
    }
    /**
     * @private
     * @param params
     * @param cb
     */
    saveCompleteWindowState(params = {}, cb = Function.prototype) {
        this.queryWindowService("saveCompleteWindowState", params, cb);
    }
    /**
     *Cancels startTabTileMonitoring. Example use is a user "escapes" out of a drag operation.
     * @param {object} params for future use
     * @private
     */
    cancelTabTileMonitoring(params = {}) {
        Logger.system.debug("FinsembleWindow.cancelTabTileMonitoring", params);
        RouterClient.transmit("TabTile.cancelTabTile", { params });
    }
    /**
     * Change the title of the current window.
     *
     * @deprecated - Set document.title in your app or use FSBL.Clients.WindowClient.setTitle()
     * @param title - the new title
     */
    setTitle(title) {
        const store = getRemoteStoreAsSingleton({
            singletonName: "WindowClient::setWindowTitle",
            server: "@@finsemble/remoteRedux/WindowServiceStore",
            slice: "windowTitleBar",
            emptyStore,
            dispatchOnly: true,
        });
        store.dispatch(actions.setAPITitle({
            title,
        }));
    }
    /**
     * Get all options related to the current window
     *
     * @param [cb]
     * @example
     * const {err, data} = await finsembleWindow.getOptions();
     * // data looks like: {acceptFirstMouse: true, addToWorkspace: true, ...}
     *
     * // Sync alternative
     * finsembleWindow.getOptions((err, data) => {
     *   // data looks like: {acceptFirstMouse: true, addToWorkspace: true, ...}
     * })
     */
    getOptions(cb) {
        return new Promise((resolve) => {
            this.queryWindowService("getOptions", {}, (err, data) => {
                cb === null || cb === void 0 ? void 0 : cb(err, data);
                resolve({ err, data });
            });
        });
    }
    /**
     * Form a docking group with any adjacent windows.
     * This is the equivalent of clicking the "Attach Windows" icon in the titlebar, if it's available.
     *
     * @example
     * finsembleWindow.formGroup()
     */
    formGroup() {
        RouterClient.transmit("DockingService.formGroup", { windowName: this.name });
    }
    /**
     * Leave a docking group
     * This is the equivalent of clicking the "Detach Window" icon in the titlebar, if it's available.
     *
     * @example
     * finsembleWindow.ejectFromGroup()
     */
    ejectFromGroup() {
        RouterClient.query("DockingService.leaveGroup", { name: this.name }, () => { });
    }
}
FinsembleWindow.WINDOWSTATE = WINDOWSTATE;
// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// The window wrappers
// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 * Legacy function. Insteady, use the `getInstance` method.
 */
FinsembleWindow.wrap = FinsembleWindow.getInstance;
/**
 * Creating wraps is expensive, involving a router query to the window service. The static member
 * `cache` is used to store these handles so that they can be used frequently.
 */
FinsembleWindow.cache = {};
/**
 * @private
 * @param windowName
 */
FinsembleWindow._windowReady = function (windowName) {
    Logger.system.debug(`windowServiceReady: ${windowName} starting`);
    let subscribeId;
    const promiseResolver = async (resolve) => {
        // Subscribe handler for component state. Once new state is retrieved, resolve out of _windowReady
        // This is a closure so it easily has access to the promise resolve method.
        const onComponentStateChanged = (err, response) => {
            const { state } = response.data;
            Logger.system.debug(`windowServiceReady: ${windowName} state change: ${state}`);
            switch (state) {
                // if ready state or any state beyond
                case "ready":
                case "reloading":
                case "closing":
                    Logger.system.debug(`windowServiceReady: ${windowName} ${state}`);
                    RouterClient.unsubscribe(subscribeId);
                    resolve();
                    break;
                default:
                    break;
            }
        };
        // wait only for components managed by the window service
        Logger.system.debug(`windowServiceReady: ${windowName} waiting`);
        subscribeId = RouterClient.subscribe(`Finsemble.Component.State.${windowName}`, onComponentStateChanged);
    };
    return new Promise(promiseResolver);
};
//# sourceMappingURL=FinsembleWindow.js.map