"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Tasks = exports.TaskState = void 0;
const error_1 = require("../utils/error");
var TaskState;
(function (TaskState) {
    TaskState[TaskState["Pending"] = 0] = "Pending";
    TaskState[TaskState["Running"] = 1] = "Running";
    TaskState[TaskState["Done"] = 2] = "Done";
    TaskState[TaskState["Failed"] = 3] = "Failed";
})(TaskState = exports.TaskState || (exports.TaskState = {}));
class Tasks {
    constructor(graph) {
        this.promises = new Set();
        this.tasks = new Map(graph.nodes.map((node) => [
            node.step.id,
            { node, state: TaskState.Pending },
        ]));
    }
    wait() {
        return Promise.race(this.promises);
    }
    run(run) {
        const promise = Promise.resolve()
            .then(run)
            .finally(() => this.promises.delete(promise));
        this.promises.add(promise);
    }
    done() {
        return (!this.promises.size &&
            !Array.from(this.tasks.values()).some((task) => {
                const state = this.state(task);
                return state === TaskState.Pending || state === TaskState.Running;
            }));
    }
    state(task) {
        if (task) {
            if (task.state === TaskState.Running || task.state === TaskState.Failed) {
                return task.state;
            }
            for (const dep of task.node.parents) {
                const depTask = this.get(dep);
                const depState = this.state(depTask);
                if (depState === TaskState.Pending || depState === TaskState.Failed) {
                    return depState;
                }
            }
            return task.state;
        }
        else {
            for (const task of this.tasks.values()) {
                if (task.state === TaskState.Failed ||
                    task.state === TaskState.Running) {
                    return task.state;
                }
            }
            for (const task of this.tasks.values()) {
                if (task.state === TaskState.Pending) {
                    return task.state;
                }
            }
            return TaskState.Done;
        }
    }
    get(node) {
        var _a;
        return ((_a = this.tasks.get(node.step.id)) !== null && _a !== void 0 ? _a : (0, error_1.error)(`Step "${node.step.id}" not foun`));
    }
    ready(task) {
        if (task.state !== TaskState.Pending) {
            return false;
        }
        return task.node.parents.every((parent) => this.get(parent).state === TaskState.Done);
    }
    queue(graph) {
        return graph.nodes
            .map((node) => this.get(node))
            .filter((task) => this.ready(task));
    }
}
exports.Tasks = Tasks;
//# sourceMappingURL=task.js.map