/*!
 * Copyright 2017 - 2020 by ChartIQ, Inc.
 * All rights reserved.
 */
// NOTE: SystemManagerClient is currently located in common but accessible on FSBL.  We have not decided yet whether or not to expose it like the other clients.
import { RouterClient } from "../clients/routerClient";
import { Logger } from "../clients/logger";
import { ALL_BOOT_STAGES } from "../platform/services/systemManager/_constants";
import { SYSLOG_CHANNEL, STAGE_CHANNEL, SHOW_SYSLOG_CHANNEL, HIDE_SYSLOG_CHANNEL, } from "../platform/services/systemManager/_constants";
import { statusChannel, checkpointChannel } from "../platform/services/systemManager/common";
/**
 * Singleton API to Finsemble System Manager
 */
class SystemManagerClient {
    constructor() {
        this.startedElements = {};
    }
    /**
     * Publishes boot status for the service or component (or boot task) being started.  This method is used internally in FSBL and baseService and not directly called.
     * @param name the name of the service or component or module
     * @param type the type category ("services" or "components")
     * @param state the state ("completed" or "failed")
     *
     * @private
     */
    publishBootStatus(name, type, state, error) {
        Logger.system.debug("publishBootStatus", name, type, state);
        RouterClient.publish(statusChannel(name), { name, type, state, error });
    }
    /**
     * Waits for a specific boot stage
     * @param stage the stage to wait for
     * @param when wait until either "stageEntered" or "stageCompleted"
     * @param= [callback]
     * @returns a promise
     *
     * @example
     *
     * 	await SystemManagerClient.waitForBootStage("authentication", "stageCompleted");
     *
     * 	SystemManagerClient.waitForBootStage("authentication", "stageCompleted", () => {
     *		RouterClient.publish(Constants.APPLICATION_STATE_CHANNEL, { state: "authenticated" });
     * 	});
     *
     */
    waitForBootStage(stage, when, callback = Function.prototype) {
        const waitForBootStageCompletionPromiseResolver = (resolve, reject) => {
            Logger.system.debug("SystemManagerClient.waitForBootStage entry", stage, when);
            const stageIndex = ALL_BOOT_STAGES.indexOf(stage);
            if (stage === "microkernel" && when === "stageEntered") {
                Logger.system.error("Cannot wait on `stageEntered` for microkernel because router isn't up yet. So will instead wait for microkernel stage complete.");
            }
            // receives startup state from services -- see SystemManagerClient.publishBootStatus
            const subscribeId = RouterClient.subscribe(STAGE_CHANNEL, (err, notify) => {
                Logger.system.debug("SystemManagerClient.waitForBootStage new stage", notify.data.stage, subscribeId);
                if (err) {
                    Logger.system.error("SystemManagerClient.waitForBootStage subscribe error", err);
                    callback(err);
                    reject(err);
                }
                else if (stageIndex === -1) {
                    // if illegal stage was input
                    err = "illegal stage argument";
                    Logger.system.debug("SystemManagerClient.waitForBootStage subscribe error", err, stage);
                    callback(err);
                    reject(err);
                }
                else {
                    // note the following section handles cases where waitForBootStage might be invoked after the stage has been enter or passed
                    const currentStageIndex = ALL_BOOT_STAGES.indexOf(notify.data.stage);
                    Logger.system.debug("SystemManagerClient.waitForBootStage new stage", notify.data, subscribeId);
                    // when the stage before completes (or anytime after) then done for "stageEntered"
                    if (when === "stageEntered" && currentStageIndex + 1 >= stageIndex) {
                        Logger.system.debug("SystemManagerClient.waitForBootStage stageEntered", stage, subscribeId, callback.name);
                        callback();
                        resolve();
                        RouterClient.unsubscribe(subscribeId);
                        // when current stage matches (or comes after) given stage, then done for "stageCompleted"
                    }
                    else if (when === "stageCompleted" && currentStageIndex >= stageIndex) {
                        Logger.system.debug("SystemManagerClient.waitForBootStage completed", stage, subscribeId);
                        callback();
                        resolve();
                        RouterClient.unsubscribe(subscribeId);
                    }
                    else {
                        Logger.system.debug(`SystemManagerClient.waitForBootStage else currentStageIndex=${currentStageIndex} stageIndex=${stageIndex} `, currentStageIndex, stageIndex, stage, subscribeId);
                    }
                }
            });
        };
        return new Promise(waitForBootStageCompletionPromiseResolver);
    }
    /**
     * Waits for a specific service (or component or boot task) to be started.
     *
     * @param name the name of the service/boot task/component (e.g. "storageService")
     * to wait for
     * @param callback function to be called when the startup process has completed or error ocurred.
     *
     * @example
     *
     * 	await SystemManagerClient.waitForStartup("configService");
     *
     *	SystemManagerClient.waitForStartup("dataStoreService", () => {
     *		RouterClient.publish(Constants.APPLICATION_STATE_CHANNEL, { state: "configuring" });
     *	});
     *
     */
    waitForStartup(name, callback = Function.prototype) {
        return new Promise((resolve, reject) => {
            if (this.startedElements[name]) {
                resolve();
                return;
            }
            Logger.system.debug(`SystemManagerClient.waitForStartup.${name}`, name);
            // receives startup state from services -- see SystemManagerClient.publishBootStatus
            const subscribeId = RouterClient.subscribe(statusChannel(name), (err, notify) => {
                Logger.system.debug("SystemManagerClient.waitForStartup subscribe", name, err, notify);
                if (err) {
                    Logger.system.error("SystemManagerClient.waitForStartup subscribe error", err);
                    callback(err);
                    this.startedElements[name] = false;
                    reject(err);
                }
                else if (notify.data.name === name && notify.data.state === "completed") {
                    Logger.system.debug("SystemManagerClient.waitForStartup completed", name);
                    this.startedElements[name] = true;
                    callback();
                    resolve();
                    RouterClient.unsubscribe(subscribeId);
                }
            });
        });
    }
    /**
     * Publishes a checkpoints status. This must be done for any checkpoint so the SystemManager will know if the checkpoint succeeded or not
     * @param windowName the name of the window publishing the checkpoint)
     * @param checkpointName the name of the checkpoint (as defined in config)
     * @param state the state for the checkpoint, either "completed" or "failed"
     *
     * @example
     *
     * 	SystemManagerClient.publishCheckpointState("workspaceService", "importedLegacyWorkspaces", "completed");
     *
     */
    publishCheckpointState(windowName, checkpointName, state) {
        //console.log("publishCheckpoint", windowName, checkpointName, state, checkpointChannel(windowName, checkpointName));
        Logger.system.debug("publishCheckpoint", windowName, checkpointName, state, checkpointChannel(windowName, checkpointName));
        RouterClient.publish(checkpointChannel(windowName, checkpointName), {
            windowName,
            checkpointName,
            state,
        });
    }
    /**
     * Shows System Log window and bring its to front.
     */
    showSystemLog() {
        Logger.system.debug("SystemManagerClient.showSystemLog");
        RouterClient.transmit(SHOW_SYSLOG_CHANNEL, true);
    }
    /**
     * Hides System Log window.
     */
    hideSystemLog() {
        Logger.system.debug("SystemManagerClient.hideSystemLog");
        RouterClient.transmit(HIDE_SYSLOG_CHANNEL, true);
    }
    /**
     * Displays message on the system log
     * @param params generally this is TBD until real system log is written
     * @param params.error if true then the log message is an error
     * @param params.notification if true then the log message is a notification
     * @param message the message string to log
     *
     * @example
     *
     * 	SystemManagerClient.systemLog({ error: true}, errorMsg);
     *  SystemManagerClient.systemLog({ notification: true }, "Notification: " + message);
     *
     */
    systemLog(params, logMessage) {
        Logger.system.debug("SystemManagerClient.systemLog", params, logMessage);
        RouterClient.transmit(SYSLOG_CHANNEL, { params, logMessage });
    }
}
const systemManagerClient = new SystemManagerClient();
export default systemManagerClient;
//# sourceMappingURL=systemManagerClient.js.map