import { isAstNode as a, isReference as u } from "../syntax-tree.js";
import { TreeStreamImpl as s, StreamImpl as d, DONE_RESULT as l } from "./stream.js";
import { inRange as I } from "./cst-utils.js";
function p(e) {
  for (const [r, n] of Object.entries(e))
    r.startsWith("$") || (Array.isArray(n) ? n.forEach((t, o) => {
      a(t) && (t.$container = e, t.$containerProperty = r, t.$containerIndex = o);
    }) : a(n) && (n.$container = e, n.$containerProperty = r));
}
function g(e, r) {
  let n = e;
  for (; n; ) {
    if (r(n))
      return n;
    n = n.$container;
  }
}
function $(e) {
  const n = h(e).$document;
  if (!n)
    throw new Error("AST node has no document.");
  return n;
}
function h(e) {
  for (; e.$container; )
    e = e.$container;
  return e;
}
function y(e, r) {
  if (!e)
    throw new Error("Node must be an AstNode.");
  const n = r == null ? void 0 : r.range;
  return new d(() => ({
    keys: Object.keys(e),
    keyIndex: 0,
    arrayIndex: 0
  }), (t) => {
    for (; t.keyIndex < t.keys.length; ) {
      const o = t.keys[t.keyIndex];
      if (!o.startsWith("$")) {
        const i = e[o];
        if (a(i)) {
          if (t.keyIndex++, c(i, n))
            return { done: !1, value: i };
        } else if (Array.isArray(i)) {
          for (; t.arrayIndex < i.length; ) {
            const x = t.arrayIndex++, f = i[x];
            if (a(f) && c(f, n))
              return { done: !1, value: f };
          }
          t.arrayIndex = 0;
        }
      }
      t.keyIndex++;
    }
    return l;
  });
}
function N(e, r) {
  if (!e)
    throw new Error("Root node must be an AstNode.");
  return new s(e, (n) => y(n, r));
}
function v(e, r) {
  if (!e)
    throw new Error("Root node must be an AstNode.");
  return new s(e, (n) => y(n, r), { includeRoot: !0 });
}
function c(e, r) {
  var n;
  if (!r)
    return !0;
  const t = (n = e.$cstNode) === null || n === void 0 ? void 0 : n.range;
  return t ? I(t, r) : !1;
}
function R(e) {
  return new d(() => ({
    keys: Object.keys(e),
    keyIndex: 0,
    arrayIndex: 0
  }), (r) => {
    for (; r.keyIndex < r.keys.length; ) {
      const n = r.keys[r.keyIndex];
      if (!n.startsWith("$")) {
        const t = e[n];
        if (u(t))
          return r.keyIndex++, { done: !1, value: { reference: t, container: e, property: n } };
        if (Array.isArray(t)) {
          for (; r.arrayIndex < t.length; ) {
            const o = r.arrayIndex++, i = t[o];
            if (u(i))
              return { done: !1, value: { reference: i, container: e, property: n, index: o } };
          }
          r.arrayIndex = 0;
        }
      }
      r.keyIndex++;
    }
    return l;
  });
}
function E(e, r) {
  const n = e.getTypeMetaData(r.$type), t = r;
  for (const o of n.properties)
    o.defaultValue !== void 0 && t[o.name] === void 0 && (t[o.name] = m(o.defaultValue));
}
function m(e) {
  return Array.isArray(e) ? [...e.map(m)] : e;
}
export {
  E as assignMandatoryProperties,
  h as findRootNode,
  g as getContainerOfType,
  $ as getDocument,
  p as linkContentToContainer,
  N as streamAllContents,
  v as streamAst,
  y as streamContents,
  R as streamReferences
};
