"use strict";
/**
 * 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.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.ScreenshotGenerator = void 0;
const fs = require("fs");
const path = require("path");
const playwright = require("../../..");
const util = require("util");
const snapshotRouter_1 = require("./snapshotRouter");
const traceModel_1 = require("./traceModel");
const fsReadFileAsync = util.promisify(fs.readFile.bind(fs));
const fsWriteFileAsync = util.promisify(fs.writeFile.bind(fs));
class ScreenshotGenerator {
    constructor(traceStorageDir, traceModel) {
        this._rendering = new Map();
        this._lock = new Lock(3);
        this._traceStorageDir = traceStorageDir;
        this._traceModel = traceModel;
        this._browserPromise = playwright.chromium.launch();
    }
    generateScreenshot(actionId) {
        const { context, action, page } = traceModel_1.actionById(this._traceModel, actionId);
        if (!this._rendering.has(action)) {
            this._rendering.set(action, this._render(context, page, action).then(body => {
                this._rendering.delete(action);
                return body;
            }));
        }
        return this._rendering.get(action);
    }
    async _render(contextEntry, pageEntry, actionEntry) {
        const imageFileName = path.join(this._traceStorageDir, actionEntry.action.timestamp + '-screenshot.png');
        try {
            return await fsReadFileAsync(imageFileName);
        }
        catch (e) {
            // fall through
        }
        const { action } = actionEntry;
        const browser = await this._browserPromise;
        await this._lock.obtain();
        const page = await browser.newPage({
            viewport: contextEntry.created.viewportSize,
            deviceScaleFactor: contextEntry.created.deviceScaleFactor
        });
        try {
            const snapshotRouter = new snapshotRouter_1.SnapshotRouter(this._traceStorageDir);
            const snapshots = action.snapshots || [];
            const snapshotId = snapshots.length ? snapshots[0].snapshotId : undefined;
            const snapshotTimestamp = action.startTime;
            const pageUrl = await snapshotRouter.selectSnapshot(contextEntry, pageEntry, snapshotId, snapshotTimestamp);
            page.route('**/*', route => snapshotRouter.route(route));
            console.log('Generating screenshot for ' + action.action, pageUrl); // eslint-disable-line no-console
            await page.goto(pageUrl);
            try {
                const element = await page.$(action.selector || '*[__playwright_target__]');
                if (element) {
                    await element.evaluate(e => {
                        e.style.backgroundColor = '#ff69b460';
                    });
                }
            }
            catch (e) {
                console.log(e); // eslint-disable-line no-console
            }
            const imageData = await page.screenshot();
            await fsWriteFileAsync(imageFileName, imageData);
            return imageData;
        }
        catch (e) {
            console.log(e); // eslint-disable-line no-console
        }
        finally {
            await page.close();
            this._lock.release();
        }
    }
}
exports.ScreenshotGenerator = ScreenshotGenerator;
class Lock {
    constructor(maxWorkers) {
        this._callbacks = [];
        this._workers = 0;
        this._maxWorkers = maxWorkers;
    }
    async obtain() {
        while (this._workers === this._maxWorkers)
            await new Promise(f => this._callbacks.push(f));
        ++this._workers;
    }
    release() {
        --this._workers;
        const callbacks = this._callbacks;
        this._callbacks = [];
        for (const callback of callbacks)
            callback();
    }
}
//# sourceMappingURL=screenshotGenerator.js.map