/*!
 * Copyright 2017 by ChartIQ, Inc.
 * All rights reserved.
 */
import async from "async";
import { FEAGlobals } from "../../../../../common/Globals";
let appLauncherStore;
let COMPONENT_UPDATE_CHANNEL;
const Actions = {
    componentList: {},
    initialize: function (cb) {
        async.parallel([
            Actions.initializeComponentList,
            Actions.getUserDefinedComponentList,
            // eslint-disable-next-line @typescript-eslint/no-use-before-define
            setupHotkeys,
        ], (err) => {
            if (err) {
                console.error(err);
            }
            FEAGlobals.FSBL.Clients.Logger.system.debug("Actions.initialize done");
            cb();
        });
    },
    getComponentList(cb) {
        FEAGlobals.FSBL.Clients.LauncherClient.getComponentList((err, response) => {
            if (typeof err === "string") {
                throw new Error(err);
            }
            // Each AppLauncher
            FEAGlobals.FSBL.Clients.Logger.system.debug("getComponentList from LauncherClient", response);
            Actions.filterComponents(response);
            if (cb) {
                cb();
            }
        });
    },
    initializeComponentList(cb) {
        const self = Actions;
        let firstTime = true;
        // When an app launcher button is clicked, it sends over the types of components that the app launcher can spawn. We assign that data to an object in the windowClient, and then use that to render the app launcher.
        FEAGlobals.FSBL.Clients.RouterClient.subscribe(COMPONENT_UPDATE_CHANNEL, (_err, response) => {
            if (!FEAGlobals.FSBL.Clients.WindowClient.options.customData.spawnData) {
                FEAGlobals.FSBL.Clients.WindowClient.options.customData.spawnData = {};
            }
            Object.assign(FEAGlobals.FSBL.Clients.WindowClient.options.customData.spawnData, response.data);
            if (firstTime) {
                // only update component list the first time to eliminate re-rendering the menu
                Actions.getComponentList(cb);
                firstTime = false;
            }
        });
        // Whenever we add or remove a component, this event is fired. We get a list of all components, then filter it out to include only the ones that this particular launcher is capable of spawning.
        FEAGlobals.FSBL.Clients.RouterClient.subscribe("Launcher.update", async (err, response) => {
            FEAGlobals.FSBL.Clients.Logger.system.debug("list updated", err, response);
            if (err) {
                return console.error(err);
            }
            const config = await FEAGlobals.FSBL.Clients.ConfigClient.get(["iocd", "alphabetizeApps"]);
            // TODO, eliminate once lodash.cloneDeep has been fixed in @interopio/core
            if (config) {
                const entries = Object.entries(response.data.componentList);
                // Sort the entries array based on keys
                const newEntries = entries.sort((a, b) => {
                    if (a[0] < b[0])
                        return -1;
                    if (a[0] > b[0])
                        return 1;
                    return 0;
                });
                // Convert sorted entries back to an object
                response.data.componentList = Object.fromEntries(newEntries);
            }
            self.filterComponents(response.data.componentList);
        });
    },
    // get quick components that the user created from storage.
    getUserDefinedComponentList(cb) {
        return cb();
    },
    // saves quick components
    saveCustomComponents() {
        const UDCs = {};
        const components = Object.keys(Actions.componentList);
        for (let i = 0; i < components.length; i++) {
            const config = Actions.componentList[components[i]];
            if (config.component && config.component.isUserDefined) {
                UDCs[config.component.type] = config;
            }
        }
        FEAGlobals.FSBL.Clients.StorageClient.save({
            topic: "finsemble",
            key: "userDefinedComponents",
            value: UDCs,
        });
    },
    /**
     * Produce a filtered component list based on the settings for this menu (either "mode" or "list").
     *
     * Components will only be added to the returned list if they match the specified mode or
     * are found in the specified list
     */
    processSettings(settings, components) {
        let componentList = {};
        const keys = Object.keys(components);
        if (settings.mode) {
            const settingsMode = Array.isArray(settings.mode) ? settings.mode : [settings.mode];
            keys.forEach((componentType) => {
                var _a;
                const config = components[componentType];
                const mode = ((_a = config === null || config === void 0 ? void 0 : config.component) === null || _a === void 0 ? void 0 : _a.mode) || [""];
                const coponentMode = Array.isArray(mode) ? mode : [mode];
                const commonModes = coponentMode.filter((n) => settingsMode.indexOf(n) !== -1);
                // If the current mode isn't in the list of modes for the component then don't include it in our list
                if (commonModes.length) {
                    componentList[componentType] = components[componentType];
                }
            });
        }
        if (settings.list) {
            const commonItems = settings.list.filter((n) => keys.indexOf(n) !== -1);
            for (let i = 0; i < commonItems.length; i++) {
                componentList[commonItems[i]] = components[commonItems[i]];
            }
        }
        return componentList;
    },
    // This filters components based on the mode and list settings in customData
    // Available settings are list - where you list specific individual component Types, mode - which piggybacks on config.mode and lists all components where the mode matches
    // If neither mode not list are set, all components are shown
    // Custom Components are always shown
    filterComponents(components = {}) {
        var _a;
        const settings = (_a = FEAGlobals.FSBL.Clients.WindowClient.getSpawnData()) !== null && _a !== void 0 ? _a : {};
        this.componentList = settings.mode || settings.list ? this.processSettings(settings, components) : components;
        FEAGlobals.FSBL.Clients.Logger.system.debug("appLauncher filterComponents", this.componentList, "settings", settings, "customData", FEAGlobals.FSBL.Clients.WindowClient.options.customData);
        appLauncherStore === null || appLauncherStore === void 0 ? void 0 : appLauncherStore.set(["componentList"], this.componentList);
        this.saveCustomComponents();
    },
    // Handler for when the user wants to remove a quick component.
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    handleRemoveCustomComponent(componentName, cb = (wasDeconsted) => { }) {
        const self = this;
        FEAGlobals.FSBL.Clients.DialogManager.open("YesNoDialog", {
            title: "Delete this App?",
            question: `Are you sure you would like to delete "${componentName}"?`,
            affirmativeResponseLabel: "Delete",
            showNegativeButton: false,
        }, (err, response) => {
            // If the user chooses "affirmative" then delete the component.
            // We should never get an error, but if we do then go ahead and delete the component too.
            if (err || response.choice === "affirmative") {
                cb(true);
                self.removeCustomComponent(componentName);
            }
            else {
                cb(false);
            }
        });
    },
    // Remove the component, notify others.
    removeCustomComponent(componentName) {
        FEAGlobals.FSBL.Clients.LauncherClient.removeUserDefinedComponent({
            name: componentName,
        }, (err) => {
            if (err) {
                return console.error(err);
            }
            Actions.getComponentList();
        });
    },
    // Hide the window.
    hideWindow() {
        FEAGlobals.finsembleWindow.hide();
    },
    // Spawn a component.
    launchComponent(config, params, cb) {
        // Actions.hideWindow();
        const defaultParams = {
            addToWorkspace: true,
            monitor: "mine",
            options: { customData: {} },
        };
        params = Object.assign(defaultParams, params);
        if (!params.options.customData) {
            params.options.customData = {};
        }
        if (!params.options.customData.component) {
            params.options.customData.component = {};
        }
        if (config.component.windowGroup) {
            params.groupName = config.component.windowGroup;
        }
        FEAGlobals.FSBL.Clients.LauncherClient.spawn(config.component.type, params, (_err, windowInfo) => {
            if (cb) {
                cb(windowInfo === null || windowInfo === void 0 ? void 0 : windowInfo.windowIdentifier);
            }
        });
    },
};
function createLocalStore(done) {
    const defaultData = {
        componentList: {},
        monitorDimensions: {},
    };
    FEAGlobals.FSBL.Clients.DistributedStoreClient.createStore({ store: "Finsemble-AppLauncher-Local-Store", values: defaultData }, (_err, store) => {
        appLauncherStore = store;
        done();
    });
}
function getWindowGroupStore(done) {
    FEAGlobals.FSBL.Clients.DistributedStoreClient.createStore({ global: true, store: "Finsemble-WindowGroups" }, () => {
        done();
    });
}
function initialize(cb) {
    COMPONENT_UPDATE_CHANNEL = `${FEAGlobals.finsembleWindow.name}.ComponentsToRender`;
    FEAGlobals.FSBL.Clients.RouterClient.addPubSubResponder(COMPONENT_UPDATE_CHANNEL, {});
    async.parallel([createLocalStore, getWindowGroupStore, Actions.initialize], (err) => {
        if (err) {
            console.error(err);
        }
        FEAGlobals.FSBL.Clients.Logger.system.debug("appLauncherstore init done");
        cb(appLauncherStore);
    });
}
const keys = {};
function setupHotkeys(cb) {
    FEAGlobals.FSBL.Clients.RouterClient.subscribe("humanInterface.keydown", (_err, response) => {
        if (!keys[response.data.key]) {
            keys[response.data.key] = {};
        }
        keys[response.data.key] = true;
        if (keys[160] && keys[162] && keys[68] && Actions.componentList["Advanced Chart"]) {
            FEAGlobals.FSBL.Clients.LauncherClient.spawn("Advanced Chart", { addToWorkspace: true, monitor: "mine" });
        }
    });
    FEAGlobals.FSBL.Clients.RouterClient.subscribe("humanInterface.keyup", (_err, response) => {
        if (!keys[response.data.key]) {
            keys[response.data.key] = {};
        }
        keys[response.data.key] = false;
    });
    return cb();
}
const getStore = () => appLauncherStore;
class StoreManager {
    constructor() {
        this.initialized = false;
        this.initializing = false;
        this.callbacks = [];
        this.store = null;
    }
    initialize() {
        if (this.initializing)
            return;
        this.initializing = true;
        initialize((store) => {
            this.initialized = true;
            this.store = store;
            this.callbacks.forEach((cb) => cb(store));
        });
    }
    addInitializedListener(cb) {
        if (this.initialized && this.store)
            return cb(this.store);
        this.callbacks.push(cb);
    }
    removeInitializedListener(cb) {
        this.callbacks = this.callbacks.filter((entry) => entry !== cb);
    }
}
const storeManager = new StoreManager();
export { storeManager, initialize, appLauncherStore as Store, Actions, getStore };
//# sourceMappingURL=appLauncherStore.js.map