"use strict";
/**
 * Copyright 2021 Google LLC.
 * Copyright (c) Microsoft Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MapperCdpConnection = void 0;
const debug_1 = __importDefault(require("debug"));
const SimpleTransport_js_1 = require("./SimpleTransport.js");
const debugInternal = (0, debug_1.default)('bidi:mapper:internal');
const debugInfo = (0, debug_1.default)('bidi:mapper:info');
const debugOthers = (0, debug_1.default)('bidi:mapper:debug:others');
// Memorizes a debug creation
const loggers = new Map();
const getLogger = (type) => {
    const prefix = `bidi:mapper:${type}`;
    let logger = loggers.get(prefix);
    if (!logger) {
        logger = (0, debug_1.default)(prefix);
        loggers.set(prefix, logger);
    }
    return logger;
};
class MapperCdpConnection {
    #cdpConnection;
    #mapperCdpClient;
    #bidiSession;
    static async create(cdpConnection, mapperTabSource, verbose, mapperOptions) {
        try {
            const mapperCdpClient = await this.#initMapper(cdpConnection, mapperTabSource, verbose, mapperOptions);
            return new MapperCdpConnection(cdpConnection, mapperCdpClient);
        }
        catch (e) {
            cdpConnection.close();
            throw e;
        }
    }
    constructor(cdpConnection, mapperCdpClient) {
        this.#cdpConnection = cdpConnection;
        this.#mapperCdpClient = mapperCdpClient;
        this.#bidiSession = new SimpleTransport_js_1.SimpleTransport(async (message) => await this.#sendMessage(message));
        this.#mapperCdpClient.on('Runtime.bindingCalled', this.#onBindingCalled);
        this.#mapperCdpClient.on('Runtime.consoleAPICalled', this.#onConsoleAPICalled);
        // Catch unhandled exceptions in the mapper.
        this.#mapperCdpClient.on('Runtime.exceptionThrown', this.#onRuntimeExceptionThrown);
    }
    async #sendMessage(message) {
        try {
            await this.#mapperCdpClient.sendCommand('Runtime.evaluate', {
                expression: `onBidiMessage(${JSON.stringify(message)})`,
            });
        }
        catch (error) {
            debugInternal('Call to onBidiMessage failed', error);
        }
    }
    close() {
        this.#cdpConnection.close();
    }
    bidiSession() {
        return this.#bidiSession;
    }
    #onBindingCalled = (params) => {
        if (params.name === 'sendBidiResponse') {
            this.#bidiSession.emit('message', params.payload);
        }
        else if (params.name === 'sendDebugMessage') {
            this.#onDebugMessage(params.payload);
        }
    };
    #onDebugMessage = (json) => {
        try {
            const log = JSON.parse(json);
            if (log.logType !== undefined && log.messages !== undefined) {
                const logger = getLogger(log.logType);
                logger(log.messages);
            }
        }
        catch {
            // Fall back to raw log in case of unknown
            debugOthers(json);
        }
    };
    #onConsoleAPICalled = (params) => {
        debugInfo('consoleAPICalled: %s %O', params.type, params.args.map((arg) => arg.value));
    };
    #onRuntimeExceptionThrown = (params) => {
        debugInfo('exceptionThrown:', params);
    };
    static async #initMapper(cdpConnection, mapperTabSource, verbose, mapperOptions) {
        debugInternal('Initializing Mapper.', mapperOptions);
        const browserClient = await cdpConnection.createBrowserSession();
        const { targetId: mapperTabTargetId } = await browserClient.sendCommand('Target.createTarget', {
            url: 'about:blank',
        });
        const { sessionId: mapperSessionId } = await browserClient.sendCommand('Target.attachToTarget', { targetId: mapperTabTargetId, flatten: true });
        const mapperCdpClient = cdpConnection.getCdpClient(mapperSessionId);
        await mapperCdpClient.sendCommand('Runtime.enable');
        await browserClient.sendCommand('Target.exposeDevToolsProtocol', {
            bindingName: 'cdp',
            targetId: mapperTabTargetId,
        });
        await mapperCdpClient.sendCommand('Runtime.addBinding', {
            name: 'sendBidiResponse',
        });
        if (verbose) {
            // Needed to request verbose logs from Mapper.
            await mapperCdpClient.sendCommand('Runtime.addBinding', {
                name: 'sendDebugMessage',
            });
        }
        // Evaluate Mapper Tab sources in the tab.
        await mapperCdpClient.sendCommand('Runtime.evaluate', {
            expression: mapperTabSource,
        });
        await mapperCdpClient.sendCommand('Runtime.evaluate', {
            expression: `window.runMapperInstance('${mapperTabTargetId}', ${JSON.stringify(mapperOptions)})`,
            awaitPromise: true,
        });
        debugInternal('Mapper is launched!');
        return mapperCdpClient;
    }
}
exports.MapperCdpConnection = MapperCdpConnection;
//# sourceMappingURL=MapperCdpConnection.js.map