import { TextDocument as l } from "../../../../../vscode-languageserver-textdocument@1.0.12/node_modules/vscode-languageserver-textdocument/lib/esm/main.js";
import { stream as m } from "../utils/stream.js";
import "../utils/uri-utils.js";
import { c as u } from "../../../../../../../_virtual/cancellation.js";
import { URI as g } from "../../../../../vscode-uri@3.0.8/node_modules/vscode-uri/lib/esm/index.js";
var n;
(function(i) {
  i[i.Changed = 0] = "Changed", i[i.Parsed = 1] = "Parsed", i[i.IndexedContent = 2] = "IndexedContent", i[i.ComputedScopes = 3] = "ComputedScopes", i[i.Linked = 4] = "Linked", i[i.IndexedReferences = 5] = "IndexedReferences", i[i.Validated = 6] = "Validated";
})(n || (n = {}));
class D {
  constructor(e) {
    this.serviceRegistry = e.ServiceRegistry, this.textDocuments = e.workspace.TextDocuments, this.fileSystemProvider = e.workspace.FileSystemProvider;
  }
  async fromUri(e, t = u.CancellationToken.None) {
    const r = await this.fileSystemProvider.readFile(e);
    return this.createAsync(e, r, t);
  }
  fromTextDocument(e, t, r) {
    return t = t ?? g.parse(e.uri), u.CancellationToken.is(r) ? this.createAsync(t, e, r) : this.create(t, e, r);
  }
  fromString(e, t, r) {
    return u.CancellationToken.is(r) ? this.createAsync(t, e, r) : this.create(t, e, r);
  }
  fromModel(e, t) {
    return this.create(t, { $model: e });
  }
  create(e, t, r) {
    if (typeof t == "string") {
      const s = this.parse(e, t, r);
      return this.createLangiumDocument(s, e, void 0, t);
    } else if ("$model" in t) {
      const s = { value: t.$model, parserErrors: [], lexerErrors: [] };
      return this.createLangiumDocument(s, e);
    } else {
      const s = this.parse(e, t.getText(), r);
      return this.createLangiumDocument(s, e, t);
    }
  }
  async createAsync(e, t, r) {
    if (typeof t == "string") {
      const s = await this.parseAsync(e, t, r);
      return this.createLangiumDocument(s, e, void 0, t);
    } else {
      const s = await this.parseAsync(e, t.getText(), r);
      return this.createLangiumDocument(s, e, t);
    }
  }
  /**
   * Create a LangiumDocument from a given parse result.
   *
   * A TextDocument is created on demand if it is not provided as argument here. Usually this
   * should not be necessary because the main purpose of the TextDocument is to convert between
   * text ranges and offsets, which is done solely in LSP request handling.
   *
   * With the introduction of {@link update} below this method is supposed to be mainly called
   * during workspace initialization and on addition/recognition of new files, while changes in
   * existing documents are processed via {@link update}.
   */
  createLangiumDocument(e, t, r, s) {
    let a;
    if (r)
      a = {
        parseResult: e,
        uri: t,
        state: n.Parsed,
        references: [],
        textDocument: r
      };
    else {
      const c = this.createTextDocumentGetter(t, s);
      a = {
        parseResult: e,
        uri: t,
        state: n.Parsed,
        references: [],
        get textDocument() {
          return c();
        }
      };
    }
    return e.value.$document = a, a;
  }
  async update(e, t) {
    var r, s;
    const a = (r = e.parseResult.value.$cstNode) === null || r === void 0 ? void 0 : r.root.fullText, c = (s = this.textDocuments) === null || s === void 0 ? void 0 : s.get(e.uri.toString()), o = c ? c.getText() : await this.fileSystemProvider.readFile(e.uri);
    if (c)
      Object.defineProperty(e, "textDocument", {
        value: c
      });
    else {
      const d = this.createTextDocumentGetter(e.uri, o);
      Object.defineProperty(e, "textDocument", {
        get: d
      });
    }
    return a !== o && (e.parseResult = await this.parseAsync(e.uri, o, t), e.parseResult.value.$document = e), e.state = n.Parsed, e;
  }
  parse(e, t, r) {
    return this.serviceRegistry.getServices(e).parser.LangiumParser.parse(t, r);
  }
  parseAsync(e, t, r) {
    return this.serviceRegistry.getServices(e).parser.AsyncParser.parse(t, r);
  }
  createTextDocumentGetter(e, t) {
    const r = this.serviceRegistry;
    let s;
    return () => s ?? (s = l.create(e.toString(), r.getServices(e).LanguageMetaData.languageId, 0, t ?? ""));
  }
}
class x {
  constructor(e) {
    this.documentMap = /* @__PURE__ */ new Map(), this.langiumDocumentFactory = e.workspace.LangiumDocumentFactory, this.serviceRegistry = e.ServiceRegistry;
  }
  get all() {
    return m(this.documentMap.values());
  }
  addDocument(e) {
    const t = e.uri.toString();
    if (this.documentMap.has(t))
      throw new Error(`A document with the URI '${t}' is already present.`);
    this.documentMap.set(t, e);
  }
  getDocument(e) {
    const t = e.toString();
    return this.documentMap.get(t);
  }
  async getOrCreateDocument(e, t) {
    let r = this.getDocument(e);
    return r || (r = await this.langiumDocumentFactory.fromUri(e, t), this.addDocument(r), r);
  }
  createDocument(e, t, r) {
    if (r)
      return this.langiumDocumentFactory.fromString(t, e, r).then((s) => (this.addDocument(s), s));
    {
      const s = this.langiumDocumentFactory.fromString(t, e);
      return this.addDocument(s), s;
    }
  }
  hasDocument(e) {
    return this.documentMap.has(e.toString());
  }
  invalidateDocument(e) {
    const t = e.toString(), r = this.documentMap.get(t);
    return r && (this.serviceRegistry.getServices(e).references.Linker.unlink(r), r.state = n.Changed, r.precomputedScopes = void 0, r.diagnostics = void 0), r;
  }
  deleteDocument(e) {
    const t = e.toString(), r = this.documentMap.get(t);
    return r && (r.state = n.Changed, this.documentMap.delete(t)), r;
  }
}
export {
  D as DefaultLangiumDocumentFactory,
  x as DefaultLangiumDocuments,
  n as DocumentState,
  l as TextDocument
};
