"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Session = void 0;
const tslib_1 = require("tslib");
const fs = tslib_1.__importStar(require("fs-extra"));
const semaphore_async_await_1 = tslib_1.__importDefault(require("semaphore-async-await"));
const actions_1 = require("../actions");
const config_1 = require("../config");
const director_1 = tslib_1.__importDefault(require("../core/director"));
const console_1 = tslib_1.__importDefault(require("../reporter/console"));
const quiet_1 = require("../reporter/quiet");
const redirect_1 = require("../reporter/redirect");
const rule_types_1 = require("../rule-types");
const selfTrackingID = "Meta::Self-Tracking";
class Session {
    constructor() {
        this.reporter = new quiet_1.QuietReporter();
        this.config = new config_1.VerdaConfig({});
        this.userSelfTrackingSet = false;
        this.userSelfTrackingGoal = null;
        this.selfTrackingGoal = null;
        this.director = new director_1.default();
        this.director.reporter = this.reporter;
        this.ruleTypes = (0, rule_types_1.bindDefaultRuleTypes)(this.config, this.director);
        const r = (0, rule_types_1.bindDefaultRulesAndFunctions)(this.config, this.director);
        this.rules = r.rules;
        this.predefinedFuncs = r.predefinedFuncs;
        this.actions = (0, actions_1.defaultActionKit)(this.config.createActionEnv());
        this.locks = new SessionLocks();
    }
    setSelfTracking(dependency) {
        this.userSelfTrackingSet = true;
        if (dependency)
            this.userSelfTrackingGoal = dependency;
    }
    setJournal(path) {
        this.config.journal = path;
    }
    deleteJournal() {
        this.config.journal = "";
    }
    bindConfig(options) {
        this.config.bind(options);
        this.director.setCapacity(this.config.jCmd);
        if (process.stderr.isTTY && process.stdout.isTTY) {
            this.reporter = new console_1.default(this.config.verbosity);
            this.director.reporter = this.reporter;
            this.config.reporter = this.reporter;
        }
        else {
            this.reporter = new redirect_1.RedirectReporter(this.config.verbosity);
            this.director.reporter = this.reporter;
            this.config.reporter = this.reporter;
        }
    }
    createSelfTrackingRule(dependency) {
        if (!this.config || !this.userSelfTrackingSet)
            return;
        const rulePath = this.config.rulePath;
        const rulePathGoal = this.rules.fileUpdated `${rulePath}`;
        const stg = this.ruleTypes.SelfTracking(selfTrackingID, async (t) => {
            await t.need(dependency || rulePathGoal);
        });
        this.selfTrackingGoal = stg `${selfTrackingID}`;
    }
    async loadJournal() {
        if (!this.config.journal)
            return;
        let json = null;
        if (await fs.pathExists(this.config.journal)) {
            try {
                json = await fs.readJson(this.config.journal);
            }
            catch (e) { }
        }
        if (json)
            json = this.director.fromJson(json);
        if (!json) {
            await fs.ensureFile(this.config.journal);
            await fs.writeFile(this.config.journal, "{}");
        }
    }
    saveJournalSync() {
        if (!this.config.journal)
            return;
        fs.ensureFileSync(this.config.journal);
        fs.writeFileSync(this.config.journal, JSON.stringify(this.director.toJson(), null, "\t"));
    }
    userCancelSync() {
        const ex = this.director.userCancelSync();
        this.reporter.systemError(ex);
        this.reporter.end(true);
        this.saveJournalSync();
    }
    async start(...args) {
        this.reporter.start();
        try {
            if (this.selfTrackingGoal) {
                await this.director.want(this.selfTrackingGoal);
                const objective = this.director.validateGoal(this.selfTrackingGoal);
                if (objective && objective.progress.revision === this.director.buildRev) {
                    this.reporter.note("Invalidating build journal due to self-tracking.");
                    this.director.invalidateJournal();
                    await this.director.want(this.selfTrackingGoal);
                }
            }
            await this.director.want(...args);
        }
        catch (e) {
            this.reporter.systemError(e);
            this.reporter.end(true);
            throw e;
        }
        this.reporter.end(false);
    }
}
exports.Session = Session;
class SessionLocks {
    constructor() {
        this.m = new Map();
    }
    alloc(key, capacity) {
        let lock = this.m.get(key);
        if (lock)
            return lock;
        lock = new semaphore_async_await_1.default(capacity || 1);
        this.m.set(key, lock);
        return lock;
    }
}
