import { Logger } from "../logger";
import { System } from "../../common/system";
import { ConfigUtilInstance as ConfigUtil } from "../../common/configUtil";
import { FEAGlobals } from "../../common/Globals";
const FreestandingRouterConfig = {
    sameDomainTransport: "FinsembleTransport",
    crossDomainTransport: "FinsembleTransport",
    transportSettings: {
        FinsembleTransport: {
            serverAddress: "ws://127.0.0.1:3376",
        },
    },
    transportName: "FinsembleTransport",
};
/**
 * Determines if the current window is in the same domain as the provided documentRoot.
 * The documentRoot is typically from the "finsemble.moduleRoot" entry of the system manifest
 * which is expanded into an absolute domain by FEA (see Manifest.ts in electron-adapter package).
 */
const isCrossDomain = (documentRoot) => {
    if (!documentRoot) {
        Logger.system.error("No documentRoot provided to RouterConfig.isCrossDomain(). Check the moduleRoot entry of the manifest.");
        return true;
    }
    const parser = document.createElement("a");
    parser.href = documentRoot;
    const isSameHost = window.location.hostname === parser.hostname;
    const isSameProtocol = window.location.protocol === parser.protocol;
    const wport = window.location.port !== undefined ? window.location.port : 80;
    const pport = parser.port !== undefined ? parser.port : 80;
    const isSamePort = wport === pport;
    const sameDomain = isSameHost && isSamePort && isSameProtocol;
    Logger.system.debug(`Transport crossDomain=${isCrossDomain} (${isSameHost}:${isSameProtocol}:${isSamePort})`);
    return !sameDomain;
};
/**
 * Returns the recommended transport given the configurations in the system manifest. The transport depends
 * on whether this window is running in the same domain as the router service (by checking the finsemble.moduleRoot entry in
 * the system manifest).  When SharedWorker is used, an isolated instance is used for FSBL services.
 */
export const getRecommendedTransport = (systemManifest, isFSBLService) => {
    const { moduleRoot, router } = systemManifest === null || systemManifest === void 0 ? void 0 : systemManifest.finsemble;
    const DefaultCrossDomainTransport = "IPCBus";
    const DefaultSameDomainTransport = "SharedWorker";
    const FSBLServiceSharedWorkerTransport = "SharedWorkerForCoreServices";
    const { sameDomainTransport = DefaultSameDomainTransport, crossDomainTransport = DefaultCrossDomainTransport } = router !== null && router !== void 0 ? router : {};
    let transport = isCrossDomain(moduleRoot) ? crossDomainTransport : sameDomainTransport;
    // If shared worker is the transport and the window is an FSBL Service, then give the window an isolated transport just for FSBL services.  This will reduce contention and improve throughput during high traffic.
    if (isFSBLService && transport === DefaultSameDomainTransport) {
        transport = FSBLServiceSharedWorkerTransport;
    }
    return transport;
};
/**
 * Converts a manifest into a RouterConfig object which can be used to start the router.
 */
const routerConfigFromManifest = (systemManifest, windowName, isFSBLService = false) => {
    var _a, _b, _c;
    Logger.system.log("WINDOW LIFECYCLE:STARTUP:RouterClient:routerConfigFromManifest", windowName, isFSBLService);
    // If manifest is a string, then there was an error getting the manifest because in a separate application
    if (!systemManifest || typeof systemManifest === "string") {
        Logger.system.error("WINDOW LIFECYCLE:STARTUP:RouterClient:routerConfigFromManifest failed -- fatal error. No manifest found.", systemManifest);
        return {
            ...FreestandingRouterConfig,
            windowName,
        };
    }
    else {
        const finConfig = systemManifest.finsemble;
        // Config for transportSettings is preferred. finsemble.IAC is deprecated but might still be floating around in production.
        const transportSettings = (_c = (_b = (_a = finConfig === null || finConfig === void 0 ? void 0 : finConfig.router) === null || _a === void 0 ? void 0 : _a.transportSettings) !== null && _b !== void 0 ? _b : finConfig === null || finConfig === void 0 ? void 0 : finConfig.IAC) !== null && _c !== void 0 ? _c : {};
        const routerConfig = {
            windowName,
            routerDomainRoot: finConfig.moduleRoot,
            transportName: getRecommendedTransport(systemManifest, isFSBLService),
            transportSettings,
        };
        return routerConfig;
    }
};
/**
 * Retrieves a router configuration given a windowName, optional transportSettings and optional systemManifest.
 * If a systemManifest is provided (e.g. FSBLDesktop) then the router config from the manifest will be used
 * otherwise it will default to using IAC (FinsembleTransport). The default IAC port of 127.0.0.1:3376 will
 * be used unless transportSettings is passed in to override it.
 */
export const getRouterConfig = ({ windowName, systemManifest, transportSettings, isFSBLService, }) => {
    if (systemManifest) {
        // FEA
        return routerConfigFromManifest(systemManifest, windowName, isFSBLService);
    }
    else {
        // Freestanding
        return {
            ...FreestandingRouterConfig,
            windowName,
            transportSettings: transportSettings !== null && transportSettings !== void 0 ? transportSettings : {},
        };
    }
};
/** Converts System.Window.getCurrent().getOptions() into a simple async call */
export const getSystemStartupData = async () => new Promise((resolve) => {
    System.Window.getCurrent().getOptions((options) => {
        FEAGlobals.fin.log("Preload: Completed System.Window.getCurrent().getOptions");
        resolve(options);
    });
});
/**
 * Returns a system manifest that has been run through the config resolver to replace
 * variables with absolute paths (e.g. $applicationRoot, $moduleRoot)
 */
export const getManifestFromStartupData = (systemStartupData) => {
    /**
     * systemStartupData.manifest contains the startup manifest, before the imports are processed.
     * At early boot stages this is all that is available. Once the entire manifest has been processed
     * for imports it becomes available in systtemStartupData.customData.manifest. For the purposes
     * of system startup it really doesn't matter which we use because all the important entries are
     * in the system manifest.
     */
    let systemManifest = systemStartupData === null || systemStartupData === void 0 ? void 0 : systemStartupData.manifest;
    if (systemManifest === null || systemManifest === void 0 ? void 0 : systemManifest.finsemble)
        ConfigUtil.resolveManifestMacros(systemManifest, systemManifest.finsemble);
    return systemManifest;
};
//# sourceMappingURL=RouterConfig.js.map