import { Profile } from "./Profile.js";
import { TraceEvent } from "./TraceEvent.js";
import {downloadAsFile} from "../../../binary/downloadAsFile.js";

export class ConcurrentExecutorProfiler {
    constructor() {
        /**
         *
         * @type {ConcurrentExecutor|null}
         */
        this.executor = null;

        /**
         * Active profile
         * @type {Profile|null}
         */
        this.profile = null;

        this.__task_id_counter = 0;
        /**
         *
         * @type {Map<Task, number>}
         * @private
         */
        this.__task_ids = new Map();
    }

    /**
     *
     * @param {ConcurrentExecutor} executor
     */
    attach(executor) {
        this.executor = executor;
    }

    /**
     *
     * @param {Task} task
     * @private
     */
    __record_task_start(task) {
        const id = this.__task_id_counter++;

        this.__task_ids.set(task, id);

        const event = new TraceEvent();

        event.name = task.name;
        event.pid = 0;
        event.tid = id;
        event.cat = "task";
        event.ph = "B";
        event.ts = performance.now();

        this.profile.traceEvents.push(event);
    }

    /**
     *
     * @param {Task} task
     * @private
     */
    __record_task_end(task) {
        //get id
        let id = this.__task_ids.get(task);

        if (id === undefined) {
            id = this.__task_id_counter++;
        } else {
            // forget the task
            this.__task_ids.delete(task);
        }

        const event = new TraceEvent();

        event.name = task.name;
        event.pid = 0;
        event.tid = id;
        event.ph = "E";
        event.ts = performance.now();

        this.profile.traceEvents.push(event);

    }

    start() {
        //start new profile
        this.profile = new Profile();
        this.profile.displayTimeUnit = "ms";

        this.__task_id_counter = 0;
        this.__task_ids.clear();

        this.executor.on.task_started.add(this.__record_task_start, this);
        this.executor.on.task_completed.add(this.__record_task_end, this);
    }

    stop() {
        this.executor.on.task_started.remove(this.__record_task_start, this);
        this.executor.on.task_completed.remove(this.__record_task_end, this);
    }

    /**
     * Prompts browser to save profile.
     * Format is compatible with chrome://tracing
     * @see https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit
     */
    save() {
        downloadAsFile(JSON.stringify(this.profile.toJSON()), 'profile.json', 'text/json');
    }
}
