import { stream } from "../utils/stream.js";
import { cancellation_exports } from "../utils/cancellation.js";
import { TextDocument } from "../../../vscode-languageserver-textdocument/lib/esm/main.js";
import { URI } from "../../../vscode-uri/lib/esm/index.js";
import { UriTrie } from "../utils/uri-utils.js";
var DocumentState;
(function(e) {
	e[e.Changed = 0] = "Changed", e[e.Parsed = 1] = "Parsed", e[e.IndexedContent = 2] = "IndexedContent", e[e.ComputedScopes = 3] = "ComputedScopes", e[e.Linked = 4] = "Linked", e[e.IndexedReferences = 5] = "IndexedReferences", e[e.Validated = 6] = "Validated";
})(DocumentState ||= {});
var DefaultLangiumDocumentFactory = class {
	constructor(e) {
		this.serviceRegistry = e.ServiceRegistry, this.textDocuments = e.workspace.TextDocuments, this.fileSystemProvider = e.workspace.FileSystemProvider;
	}
	async fromUri(e, a = cancellation_exports.CancellationToken.None) {
		let o = await this.fileSystemProvider.readFile(e);
		return this.createAsync(e, o, a);
	}
	fromTextDocument(e, a, s) {
		return a ??= URI.parse(e.uri), cancellation_exports.CancellationToken.is(s) ? this.createAsync(a, e, s) : this.create(a, e, s);
	}
	fromString(e, a, o) {
		return cancellation_exports.CancellationToken.is(o) ? this.createAsync(a, e, o) : this.create(a, e, o);
	}
	fromModel(e, i) {
		return this.create(i, { $model: e });
	}
	create(e, i, a) {
		if (typeof i == "string") {
			let o = this.parse(e, i, a);
			return this.createLangiumDocument(o, e, void 0, i);
		} else if ("$model" in i) {
			let a = {
				value: i.$model,
				parserErrors: [],
				lexerErrors: []
			};
			return this.createLangiumDocument(a, e);
		} else {
			let o = this.parse(e, i.getText(), a);
			return this.createLangiumDocument(o, e, i);
		}
	}
	async createAsync(e, i, a) {
		if (typeof i == "string") {
			let o = await this.parseAsync(e, i, a);
			return this.createLangiumDocument(o, e, void 0, i);
		} else {
			let o = await this.parseAsync(e, i.getText(), a);
			return this.createLangiumDocument(o, e, i);
		}
	}
	createLangiumDocument(e, i, a, o) {
		let s;
		if (a) s = {
			parseResult: e,
			uri: i,
			state: DocumentState.Parsed,
			references: [],
			textDocument: a
		};
		else {
			let a = this.createTextDocumentGetter(i, o);
			s = {
				parseResult: e,
				uri: i,
				state: DocumentState.Parsed,
				references: [],
				get textDocument() {
					return a();
				}
			};
		}
		return e.value.$document = s, s;
	}
	async update(e, i) {
		let a = e.parseResult.value.$cstNode?.root.fullText, o = this.textDocuments?.get(e.uri.toString()), s = o ? o.getText() : await this.fileSystemProvider.readFile(e.uri);
		if (o) Object.defineProperty(e, "textDocument", { value: o });
		else {
			let i = this.createTextDocumentGetter(e.uri, s);
			Object.defineProperty(e, "textDocument", { get: i });
		}
		return a !== s && (e.parseResult = await this.parseAsync(e.uri, s, i), e.parseResult.value.$document = e), e.state = DocumentState.Parsed, e;
	}
	parse(e, i, a) {
		return this.serviceRegistry.getServices(e).parser.LangiumParser.parse(i, a);
	}
	parseAsync(e, i, a) {
		return this.serviceRegistry.getServices(e).parser.AsyncParser.parse(i, a);
	}
	createTextDocumentGetter(e, i) {
		let o = this.serviceRegistry, s;
		return () => s ??= TextDocument.create(e.toString(), o.getServices(e).LanguageMetaData.languageId, 0, i ?? "");
	}
}, DefaultLangiumDocuments = class {
	constructor(e) {
		this.documentTrie = new UriTrie(), this.services = e, this.langiumDocumentFactory = e.workspace.LangiumDocumentFactory, this.documentBuilder = () => e.workspace.DocumentBuilder;
	}
	get all() {
		return stream(this.documentTrie.all());
	}
	addDocument(e) {
		let i = e.uri.toString();
		if (this.documentTrie.has(i)) throw Error(`A document with the URI '${i}' is already present.`);
		this.documentTrie.insert(i, e);
	}
	getDocument(e) {
		let i = e.toString();
		return this.documentTrie.find(i);
	}
	getDocuments(e) {
		let i = e.toString();
		return this.documentTrie.findAll(i);
	}
	async getOrCreateDocument(e, i) {
		let a = this.getDocument(e);
		return a || (a = await this.langiumDocumentFactory.fromUri(e, i), this.addDocument(a), a);
	}
	createDocument(e, i, a) {
		if (a) return this.langiumDocumentFactory.fromString(i, e, a).then((e) => (this.addDocument(e), e));
		{
			let a = this.langiumDocumentFactory.fromString(i, e);
			return this.addDocument(a), a;
		}
	}
	hasDocument(e) {
		return this.documentTrie.has(e.toString());
	}
	invalidateDocument(e) {
		let i = e.toString(), a = this.documentTrie.find(i);
		return a && this.documentBuilder().resetToState(a, DocumentState.Changed), a;
	}
	deleteDocument(e) {
		let i = e.toString(), a = this.documentTrie.find(i);
		return a && (a.state = DocumentState.Changed, this.documentTrie.delete(i)), a;
	}
	deleteDocuments(e) {
		let i = e.toString(), a = this.documentTrie.findAll(i);
		for (let e of a) e.state = DocumentState.Changed;
		return this.documentTrie.delete(i), a;
	}
};
export { DefaultLangiumDocumentFactory, DefaultLangiumDocuments, DocumentState };
