/**
 * 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 { LongStandingScope } from '@isomorphic/manualPromise';
import { ChannelOwner } from './channelOwner';
import { ConsoleMessage } from './consoleMessage';
import { isTargetClosedError, TargetClosedError } from './errors';
import { Events } from './events';
import { JSHandle, assertMaxArguments, parseResult, serializeArgument } from './jsHandle';
import { TimeoutSettings } from './timeoutSettings';
import { Waiter } from './waiter';
export class Worker extends ChannelOwner {
    _page; // Set for web workers.
    _context; // Set for service workers.
    _closedScope = new LongStandingScope();
    _closeReason;
    static fromNullable(worker) {
        return worker ? Worker.from(worker) : null;
    }
    static from(worker) {
        return worker._object;
    }
    constructor(parent, type, guid, initializer) {
        super(parent, type, guid, initializer);
        this._setEventToSubscriptionMapping(new Map([
            [Events.Worker.Console, 'console'],
        ]));
        this._channel.on('console', event => {
            // Note: we only receive console events here for workers from "chromium._connectToWorker".
            this.emit(Events.Worker.Console, new ConsoleMessage(this._platform, event, null, this));
        });
        this._channel.on('close', () => {
            if (this._page)
                this._page._workers.delete(this);
            if (this._context)
                this._context._serviceWorkers.delete(this);
            this.emit(Events.Worker.Close, this);
        });
        this.once(Events.Worker.Close, () => this._closedScope.close(this._closeErrorWithReason()));
    }
    _closeErrorWithReason() {
        if (this._closeReason)
            return new TargetClosedError(this._closeReason);
        return this._page?._closeErrorWithReason() || new TargetClosedError();
    }
    url() {
        return this._initializer.url;
    }
    async evaluate(pageFunction, arg) {
        assertMaxArguments(arguments.length, 2);
        const result = await this._channel.evaluateExpression({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
        return parseResult(result.value);
    }
    async evaluateHandle(pageFunction, arg) {
        assertMaxArguments(arguments.length, 2);
        const result = await this._channel.evaluateExpressionHandle({ expression: String(pageFunction), isFunction: typeof pageFunction === 'function', arg: serializeArgument(arg) });
        return JSHandle.from(result.handle);
    }
    async waitForEvent(event, optionsOrPredicate = {}) {
        return await this._wrapApiCall(async () => {
            const timeoutSettings = this._page?._timeoutSettings ?? this._context?._timeoutSettings ?? new TimeoutSettings(this._platform);
            const timeout = timeoutSettings.timeout(typeof optionsOrPredicate === 'function' ? {} : optionsOrPredicate);
            const predicate = typeof optionsOrPredicate === 'function' ? optionsOrPredicate : optionsOrPredicate.predicate;
            const waiter = Waiter.createForEvent(this, event);
            waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
            if (event !== Events.Worker.Close)
                waiter.rejectOnEvent(this, Events.Worker.Close, () => this._closeErrorWithReason());
            const result = await waiter.waitForEvent(this, event, predicate);
            waiter.dispose();
            return result;
        });
    }
    async _disconnect(options = {}) {
        this._closeReason = options.reason;
        try {
            await this._channel.disconnect(options);
        }
        catch (e) {
            if (isTargetClosedError(e))
                return;
            throw e;
        }
    }
}
//# sourceMappingURL=worker.js.map