/**
 * 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.
 */
import { Browser } from '../browser';
import { BrowserContextDispatcher } from './browserContextDispatcher';
import { CDPSessionDispatcher } from './cdpSessionDispatcher';
import { Dispatcher } from './dispatcher';
import { BrowserContext } from '../browserContext';
import { ArtifactDispatcher } from './artifactDispatcher';
import { nullProgress } from '../progress';
export class BrowserDispatcher extends Dispatcher {
    _type_Browser = true;
    _options;
    _isolatedContexts = new Set();
    constructor(scope, browser, options = {}) {
        super(scope, browser, 'Browser', { version: browser.version(), name: browser.options.name, browserName: browser.options.browserType });
        this._options = options;
        if (!options.isolateContexts) {
            this.addObjectListener(Browser.Events.Context, (context) => this._dispatchEvent('context', { context: BrowserContextDispatcher.from(this, context) }));
            this.addObjectListener(Browser.Events.Disconnected, () => this._didClose());
            if (browser._defaultContext)
                this._dispatchEvent('context', { context: BrowserContextDispatcher.from(this, browser._defaultContext) });
            for (const context of browser.contexts())
                this._dispatchEvent('context', { context: BrowserContextDispatcher.from(this, context) });
        }
    }
    _didClose() {
        this._dispatchEvent('close');
        this._dispose();
    }
    async newContext(params, progress) {
        if (params.recordVideo && this._object.attribution.playwright.options.isServer)
            params.recordVideo.dir = undefined;
        if (!this._options.isolateContexts) {
            const context = await this._object.newContext(progress, params);
            const contextDispatcher = BrowserContextDispatcher.from(this, context);
            return { context: contextDispatcher };
        }
        const context = await this._object.newContext(progress, params);
        this._isolatedContexts.add(context);
        context.on(BrowserContext.Events.Close, () => this._isolatedContexts.delete(context));
        const contextDispatcher = BrowserContextDispatcher.from(this, context);
        this._dispatchEvent('context', { context: contextDispatcher });
        return { context: contextDispatcher };
    }
    async newContextForReuse(params, progress) {
        const context = await this._object.newContextForReuse(progress, params);
        const contextDispatcher = BrowserContextDispatcher.from(this, context);
        this._dispatchEvent('context', { context: contextDispatcher });
        return { context: contextDispatcher };
    }
    async disconnectFromReusedContext(params, progress) {
        const context = this._object.contextForReuse();
        const contextDispatcher = context ? this.connection.existingDispatcher(context) : undefined;
        if (contextDispatcher) {
            await progress.race(contextDispatcher.stopPendingOperations(new Error(params.reason)));
            contextDispatcher._dispose();
        }
    }
    async close(params, progress) {
        if (this._options.ignoreStopAndKill)
            return;
        progress.metadata.potentiallyClosesScope = true;
        await this._object.close(progress, params);
    }
    async killForTests(params, progress) {
        if (this._options.ignoreStopAndKill)
            return;
        progress.metadata.potentiallyClosesScope = true;
        await this._object.killForTests(progress);
    }
    async defaultUserAgentForTest() {
        return { userAgent: this._object.userAgent() };
    }
    async newBrowserCDPSession(params, progress) {
        // Note: progress is ignored because this operation is not cancellable and should not block in the browser anyway.
        if (this._object.options.browserType !== 'chromium')
            throw new Error(`CDP session is only available in Chromium`);
        const crBrowser = this._object;
        return { session: new CDPSessionDispatcher(this, await progress.race(crBrowser.newBrowserCDPSession())) };
    }
    async startTracing(params, progress) {
        // Note: progress is ignored because this operation is not cancellable and should not block in the browser anyway.
        if (this._object.options.browserType !== 'chromium')
            throw new Error(`Tracing is only available in Chromium`);
        const crBrowser = this._object;
        await progress.race(crBrowser.startTracing(params.page ? params.page._object : undefined, params));
    }
    async stopTracing(params, progress) {
        // Note: progress is ignored because this operation is not cancellable and should not block in the browser anyway.
        if (this._object.options.browserType !== 'chromium')
            throw new Error(`Tracing is only available in Chromium`);
        const crBrowser = this._object;
        return { artifact: ArtifactDispatcher.from(this, await progress.race(crBrowser.stopTracing())) };
    }
    async startServer(params, progress) {
        return await this._object.startServer(progress, params.title, params);
    }
    async stopServer(params, progress) {
        await this._object.stopServer(progress);
    }
    async cleanupContexts() {
        await Promise.all(Array.from(this._isolatedContexts).map(context => context.close(nullProgress, { reason: 'Global context cleanup (connection terminated)' })));
    }
}
//# sourceMappingURL=browserDispatcher.js.map