"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RunProcess = void 0;
const event_1 = require("@f2/event");
const run_process_error_1 = require("./run-process.error");
class RunProcess {
    interval;
    _runner;
    name;
    _running = false;
    _nextTimeout;
    _runnerInProgress = false;
    _eventEmitter;
    constructor(interval, _runner, name) {
        this.interval = interval;
        this._runner = _runner;
        this.name = name;
        this._eventEmitter = (0, event_1.beginEventEmitter)(this);
    }
    runTick() {
        if (!this._running) {
            return;
        }
        if (this._runnerInProgress) {
            this.emit('error', new run_process_error_1.RunnerAlreadyRunningError(this.name));
            return;
        }
        this._runnerInProgress = true;
        let inTimeout = false;
        const run = () => {
            setImmediate(() => {
                this._runnerInProgress = false;
                this.runTick();
            });
        };
        const onSuccess = () => {
            if (inTimeout) {
                run();
            }
            else {
                // Quand le process a été redémarré
                if (this._running && !this._nextTimeout) {
                    run();
                }
                else {
                    this._runnerInProgress = false;
                }
            }
        };
        const onError = (err) => {
            onSuccess();
            this.emit('error', err);
        };
        const nextTimeout = setTimeout(() => {
            if (this._runnerInProgress) {
                this.emit('error', new run_process_error_1.RunnerTimeoutError(this.name));
                inTimeout = true;
                return;
            }
            this.runTick();
        }, this.interval.toMilliseconds());
        this._nextTimeout = nextTimeout;
        try {
            const result = this._runner(onSuccess, () => {
                clearTimeout(nextTimeout);
                run();
            });
            if (result && typeof result.then === 'function' && typeof result.catch === 'function') {
                result.then(onSuccess).catch(onError);
            }
            else {
                onSuccess();
            }
        }
        catch (err) {
            onError(err);
        }
    }
    start() {
        if (this._eventEmitter.listenerCount('error') === 0) {
            throw new run_process_error_1.NoErrorListenerError(this.name);
        }
        this._running = true;
        if (!this._runnerInProgress) {
            this.runTick();
        }
    }
    clear() {
        if (this._nextTimeout) {
            clearTimeout(this._nextTimeout);
            this._nextTimeout = undefined;
        }
    }
    stop() {
        this._running = false;
        this.clear();
    }
    restart() {
        this.stop();
        this.start();
    }
    setInterval(interval) {
        this.interval = interval;
        this.restart();
    }
    runNow() {
        if (this._runnerInProgress) {
            return;
        }
        this.clear();
        this.runTick();
    }
}
exports.RunProcess = RunProcess;
