import { Deferred, OperationCancelled } from "../utils/promise-utils.js";
import { event_exports } from "../utils/event.js";
var DefaultAsyncParser = class {
	constructor(e) {
		this.syncParser = e.parser.LangiumParser;
	}
	parse(e, t) {
		return Promise.resolve(this.syncParser.parse(e));
	}
}, AbstractThreadedAsyncParser = class {
	constructor(e) {
		this.threadCount = 8, this.terminationDelay = 200, this.workerPool = [], this.queue = [], this.hydrator = e.serializer.Hydrator;
	}
	initializeWorkers() {
		for (; this.workerPool.length < this.threadCount;) {
			let e = this.createWorker();
			e.onReady(() => {
				if (this.queue.length > 0) {
					let t = this.queue.shift();
					t && (e.lock(), t.resolve(e));
				}
			}), this.workerPool.push(e);
		}
	}
	async parse(t, n) {
		let r = await this.acquireParserWorker(n), i = new Deferred(), a, o = n.onCancellationRequested(() => {
			a = setTimeout(() => {
				this.terminateWorker(r);
			}, this.terminationDelay);
		});
		return r.parse(t).then((e) => {
			let t = this.hydrator.hydrate(e);
			i.resolve(t);
		}).catch((e) => {
			i.reject(e);
		}).finally(() => {
			o.dispose(), clearTimeout(a);
		}), i.promise;
	}
	terminateWorker(e) {
		e.terminate();
		let t = this.workerPool.indexOf(e);
		t >= 0 && this.workerPool.splice(t, 1);
	}
	async acquireParserWorker(n) {
		this.initializeWorkers();
		for (let e of this.workerPool) if (e.ready) return e.lock(), e;
		let r = new Deferred();
		return n.onCancellationRequested(() => {
			let e = this.queue.indexOf(r);
			e >= 0 && this.queue.splice(e, 1), r.reject(OperationCancelled);
		}), this.queue.push(r), r.promise;
	}
}, ParserWorker = class {
	get ready() {
		return this._ready;
	}
	get onReady() {
		return this.onReadyEmitter.event;
	}
	constructor(t, r, i, a) {
		this.onReadyEmitter = new event_exports.Emitter(), this.deferred = new Deferred(), this._ready = !0, this._parsing = !1, this.sendMessage = t, this._terminate = a, r((e) => {
			let t = e;
			this.deferred.resolve(t), this.unlock();
		}), i((e) => {
			this.deferred.reject(e), this.unlock();
		});
	}
	terminate() {
		this.deferred.reject(OperationCancelled), this._terminate();
	}
	lock() {
		this._ready = !1;
	}
	unlock() {
		this._parsing = !1, this._ready = !0, this.onReadyEmitter.fire();
	}
	parse(t) {
		if (this._parsing) throw Error("Parser worker is busy");
		return this._parsing = !0, this.deferred = new Deferred(), this.sendMessage(t), this.deferred.promise;
	}
};
export { AbstractThreadedAsyncParser, DefaultAsyncParser, ParserWorker };
