import { forEach as o, assign as q$1, find as _, isString as S$1, findIndex as K$1, filter as v$1, has as N } from "../../min-dash/dist/index.esm.mjs";
import { Parser as Ee$1 } from "../../saxen/dist/index.esm.mjs";
import { coerceType as S, parseNameNS as u, isSimpleType as C$1, Moddle as y } from "../../moddle/dist/index.esm.mjs";
function K(e) {
  return e.xml && e.xml.tagAlias === "lowerCase";
}
var me = {
  xsi: "http://www.w3.org/2001/XMLSchema-instance",
  xml: "http://www.w3.org/XML/1998/namespace"
}, C = "xsi:type";
function Q(e) {
  return e.xml && e.xml.serialize;
}
function Y(e) {
  return Q(e) === C;
}
function ye(e) {
  return Q(e) === "property";
}
function ve(e) {
  return e.charAt(0).toUpperCase() + e.slice(1);
}
function q(e, t) {
  return K(t) ? e.prefix + ":" + ve(e.localName) : e.name;
}
function ge(e, t) {
  var r = e.name, n = e.localName, i = t.xml && t.xml.typePrefix;
  return i && n.indexOf(i) === 0 ? e.prefix + ":" + n.slice(i.length) : r;
}
function Ne(e, t) {
  var r = u(e), n = t.getPackage(r.prefix);
  return ge(r, n);
}
function P(e) {
  return new Error(e);
}
function T(e) {
  return e.$descriptor;
}
function xe(e) {
  q$1(this, e), this.elementsById = {}, this.references = [], this.warnings = [], this.addReference = function(t) {
    this.references.push(t);
  }, this.addElement = function(t) {
    if (!t)
      throw P("expected element");
    var r = this.elementsById, n = T(t), i = n.idProperty, a;
    if (i && (a = t.get(i.name), a)) {
      if (!/^([a-z][\w-.]*:)?[a-z_][\w-.]*$/i.test(a))
        throw new Error("illegal ID <" + a + ">");
      if (r[a])
        throw P("duplicate ID <" + a + ">");
      r[a] = t;
    }
  }, this.addWarning = function(t) {
    this.warnings.push(t);
  };
}
function M() {
}
M.prototype.handleEnd = function() {
};
M.prototype.handleText = function() {
};
M.prototype.handleNode = function() {
};
function k() {
}
k.prototype = Object.create(M.prototype);
k.prototype.handleNode = function() {
  return this;
};
function z() {
}
z.prototype = Object.create(M.prototype);
z.prototype.handleText = function(e) {
  this.body = (this.body || "") + e;
};
function B(e, t) {
  this.property = e, this.context = t;
}
B.prototype = Object.create(z.prototype);
B.prototype.handleNode = function(e) {
  if (this.element)
    throw P("expected no sub nodes");
  return this.element = this.createReference(e), this;
};
B.prototype.handleEnd = function() {
  this.element.id = this.body;
};
B.prototype.createReference = function(e) {
  return {
    property: this.property.ns.name,
    id: ""
  };
};
function D(e, t) {
  this.element = t, this.propertyDesc = e;
}
D.prototype = Object.create(z.prototype);
D.prototype.handleEnd = function() {
  var e = this.body || "", t = this.element, r = this.propertyDesc;
  e = S(r.type, e), r.isMany ? t.get(r.name).push(e) : t.set(r.name, e);
};
function L() {
}
L.prototype = Object.create(z.prototype);
L.prototype.handleNode = function(e) {
  var t = this, r = this.element;
  return r ? t = this.handleChild(e) : (r = this.element = this.createElement(e), this.context.addElement(r)), t;
};
function v(e, t, r) {
  this.model = e, this.type = e.getType(t), this.context = r;
}
v.prototype = Object.create(L.prototype);
v.prototype.addReference = function(e) {
  this.context.addReference(e);
};
v.prototype.handleText = function(e) {
  var t = this.element, r = T(t), n = r.bodyProperty;
  if (!n)
    throw P("unexpected body text <" + e + ">");
  z.prototype.handleText.call(this, e);
};
v.prototype.handleEnd = function() {
  var e = this.body, t = this.element, r = T(t), n = r.bodyProperty;
  n && e !== void 0 && (e = S(n.type, e), t.set(n.name, e));
};
v.prototype.createElement = function(e) {
  var t = e.attributes, r = this.type, n = T(r), i = this.context, a = new r({}), s = this.model, o$1;
  return o(t, function(p, l) {
    var h = n.propertiesByName[l], m;
    h && h.isReference ? h.isMany ? (m = p.split(" "), o(m, function(I) {
      i.addReference({
        element: a,
        property: h.ns.name,
        id: I
      });
    })) : i.addReference({
      element: a,
      property: h.ns.name,
      id: p
    }) : (h ? p = S(h.type, p) : l !== "xmlns" && (o$1 = u(l, n.ns.prefix), s.getPackage(o$1.prefix) && i.addWarning({
      message: "unknown attribute <" + l + ">",
      element: a,
      property: l,
      value: p
    })), a.set(l, p));
  }), a;
};
v.prototype.getPropertyForNode = function(e) {
  var t = e.name, r = u(t), n = this.type, i = this.model, a = T(n), s = r.name, o2 = a.propertiesByName[s], p, l;
  if (o2 && !o2.isAttr)
    return Y(o2) && (p = e.attributes[C], p) ? (p = Ne(p, i), l = i.getType(p), q$1({}, o2, {
      effectiveType: T(l).name
    })) : o2;
  var h = i.getPackage(r.prefix);
  if (h) {
    if (p = q(r, h), l = i.getType(p), o2 = _(a.properties, function(m) {
      return !m.isVirtual && !m.isReference && !m.isAttribute && l.hasType(m.type);
    }), o2)
      return q$1({}, o2, {
        effectiveType: T(l).name
      });
  } else if (o2 = _(a.properties, function(m) {
    return !m.isReference && !m.isAttribute && m.type === "Element";
  }), o2)
    return o2;
  throw P("unrecognized element <" + r.name + ">");
};
v.prototype.toString = function() {
  return "ElementDescriptor[" + T(this.type).name + "]";
};
v.prototype.valueHandler = function(e, t) {
  return new D(e, t);
};
v.prototype.referenceHandler = function(e) {
  return new B(e, this.context);
};
v.prototype.handler = function(e) {
  return e === "Element" ? new U(this.model, e, this.context) : new v(this.model, e, this.context);
};
v.prototype.handleChild = function(e) {
  var t, r, n, i;
  if (t = this.getPropertyForNode(e), n = this.element, r = t.effectiveType || t.type, C$1(r))
    return this.valueHandler(t, n);
  t.isReference ? i = this.referenceHandler(t).handleNode(e) : i = this.handler(r).handleNode(e);
  var a = i.element;
  return a !== void 0 && (t.isMany ? n.get(t.name).push(a) : n.set(t.name, a), t.isReference ? (q$1(a, {
    element: n
  }), this.context.addReference(a)) : a.$parent = n), i;
};
function W(e, t, r) {
  v.call(this, e, t, r);
}
W.prototype = Object.create(v.prototype);
W.prototype.createElement = function(e) {
  var t = e.name, r = u(t), n = this.model, i = this.type, a = n.getPackage(r.prefix), s = a && q(r, a) || t;
  if (!i.hasType(s))
    throw P("unexpected element <" + e.originalName + ">");
  return v.prototype.createElement.call(this, e);
};
function U(e, t, r) {
  this.model = e, this.context = r;
}
U.prototype = Object.create(L.prototype);
U.prototype.createElement = function(e) {
  var t = e.name, r = u(t), n = r.prefix, i = e.ns[n + "$uri"], a = e.attributes;
  return this.model.createAny(t, i, a);
};
U.prototype.handleChild = function(e) {
  var t = new U(this.model, "Element", this.context).handleNode(e), r = this.element, n = t.element, i;
  return n !== void 0 && (i = r.$children = r.$children || [], i.push(n), n.$parent = r), t;
};
U.prototype.handleEnd = function() {
  this.body && (this.element.$body = this.body);
};
function J(e) {
  e instanceof y && (e = {
    model: e
  }), q$1(this, { lax: false }, e);
}
J.prototype.fromXML = function(e, t, r) {
  var n = t.rootHandler;
  t instanceof v ? (n = t, t = {}) : typeof t == "string" ? (n = this.handler(t), t = {}) : typeof n == "string" && (n = this.handler(n));
  var i = this.model, a = this.lax, s = new xe(q$1({}, t, { rootHandler: n })), o2 = new Ee$1({ proxy: true }), p = be();
  n.context = s, p.push(n);
  function l(u2, f, d) {
    var y2 = f(), b = y2.line, A = y2.column, g = y2.data;
    g.charAt(0) === "<" && g.indexOf(" ") !== -1 && (g = g.slice(0, g.indexOf(" ")) + ">");
    var x = "unparsable content " + (g ? g + " " : "") + `detected
	line: ` + b + `
	column: ` + A + `
	nested error: ` + u2.message;
    if (d)
      return s.addWarning({
        message: x,
        error: u2
      }), true;
    throw P(x);
  }
  function h(u2, f) {
    return l(u2, f, true);
  }
  function m() {
    var u2 = s.elementsById, f = s.references, d, y2;
    for (d = 0; y2 = f[d]; d++) {
      var b = y2.element, A = u2[y2.id], g = T(b).propertiesByName[y2.property];
      if (A || s.addWarning({
        message: "unresolved reference <" + y2.id + ">",
        element: y2.element,
        property: y2.property,
        value: y2.id
      }), g.isMany) {
        var x = b.get(g.name), E = x.indexOf(y2);
        E === -1 && (E = x.length), A ? x[E] = A : x.splice(E, 1);
      } else
        b.set(g.name, A);
    }
  }
  function I() {
    p.pop().handleEnd();
  }
  var ne = /^<\?xml /i, ie = / encoding="([^"]+)"/i, ae = /^utf-8$/i;
  function se(u2) {
    if (ne.test(u2)) {
      var f = ie.exec(u2), d = f && f[1];
      !d || ae.test(d) || s.addWarning({
        message: "unsupported document encoding <" + d + ">, falling back to UTF-8"
      });
    }
  }
  function oe(u2, f) {
    var d = p.peek();
    try {
      p.push(d.handleNode(u2));
    } catch (y2) {
      l(y2, f, a) && p.push(new k());
    }
  }
  function X(u2, f) {
    try {
      p.peek().handleText(u2);
    } catch (d) {
      h(d, f);
    }
  }
  function pe(u2, f) {
    u2.trim() && X(u2, f);
  }
  var ue = i.getPackages().reduce(function(u2, f) {
    return u2[f.uri] = f.prefix, u2;
  }, {
    "http://www.w3.org/XML/1998/namespace": "xml"
    // add default xml ns
  });
  return o2.ns(ue).on("openTag", function(u2, f, d, y2) {
    var b = u2.attrs || {}, A = Object.keys(b).reduce(function(x, E) {
      var ce = f(b[E]);
      return x[E] = ce, x;
    }, {}), g = {
      name: u2.name,
      originalName: u2.originalName,
      attributes: A,
      ns: u2.ns
    };
    oe(g, y2);
  }).on("question", se).on("closeTag", I).on("cdata", X).on("text", function(u2, f, d) {
    pe(f(u2), d);
  }).on("error", l).on("warn", h), new Promise(function(u2, f) {
    var d;
    try {
      o2.parse(e), m();
    } catch (x) {
      d = x;
    }
    var y2 = n.element;
    !d && !y2 && (d = P("failed to parse document as <" + n.type.$descriptor.name + ">"));
    var b = s.warnings, A = s.references, g = s.elementsById;
    return d ? (d.warnings = b, f(d)) : u2({
      rootElement: y2,
      elementsById: g,
      references: A,
      warnings: b
    });
  });
};
J.prototype.handler = function(e) {
  return new W(this.model, e);
};
function be() {
  var e = [];
  return Object.defineProperty(e, "peek", {
    value: function() {
      return this[this.length - 1];
    }
  }), e;
}
var we = `<?xml version="1.0" encoding="UTF-8"?>
`, Ae = /<|>|'|"|&|\n\r|\n/g, Z = /<|>|&/g;
function Te(e) {
  var t = {}, r = {}, n = {}, i = [], a = [];
  this.byUri = function(s) {
    return r[s] || e && e.byUri(s);
  }, this.add = function(s, o2) {
    r[s.uri] = s, o2 ? i.push(s) : a.push(s), this.mapPrefix(s.prefix, s.uri);
  }, this.uriByPrefix = function(s) {
    return t[s || "xmlns"];
  }, this.mapPrefix = function(s, o2) {
    t[s || "xmlns"] = o2;
  }, this.getNSKey = function(s) {
    return s.prefix !== void 0 ? s.uri + "|" + s.prefix : s.uri;
  }, this.logUsed = function(s) {
    var o2 = s.uri, p = this.getNSKey(s);
    n[p] = this.byUri(o2), e && e.logUsed(s);
  }, this.getUsed = function(s) {
    function o2(h) {
      var m = p.getNSKey(h);
      return n[m];
    }
    var p = this, l = [].concat(i, a);
    return l.filter(o2);
  };
}
function Pe(e) {
  return e.charAt(0).toLowerCase() + e.slice(1);
}
function Ee(e, t) {
  return K(t) ? Pe(e) : e;
}
function ee(e, t) {
  e.super_ = t, e.prototype = Object.create(t.prototype, {
    constructor: {
      value: e,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });
}
function te(e) {
  return S$1(e) ? e : (e.prefix ? e.prefix + ":" : "") + e.localName;
}
function Re(e) {
  return e.getUsed().filter(function(t) {
    return t.prefix !== "xml";
  }).map(function(t) {
    var r = "xmlns" + (t.prefix ? ":" + t.prefix : "");
    return { name: r, value: t.uri };
  });
}
function Se(e, t) {
  return t.isGeneric ? q$1({ localName: t.ns.localName }, e) : q$1({ localName: Ee(t.ns.localName, t.$pkg) }, e);
}
function Ue(e, t) {
  return q$1({ localName: t.ns.localName }, e);
}
function ze(e) {
  var t = e.$descriptor;
  return v$1(t.properties, function(r) {
    var n = r.name;
    if (r.isVirtual || !N(e, n))
      return false;
    var i = e[n];
    return i === r.default || i === null ? false : r.isMany ? i.length : true;
  });
}
var Me = {
  "\n": "#10",
  "\n\r": "#10",
  '"': "#34",
  "'": "#39",
  "<": "#60",
  ">": "#62",
  "&": "#38"
}, Be = {
  "<": "lt",
  ">": "gt",
  "&": "amp"
};
function re(e, t, r) {
  return e = S$1(e) ? e : "" + e, e.replace(t, function(n) {
    return "&" + r[n] + ";";
  });
}
function $e(e) {
  return re(e, Ae, Me);
}
function Ce(e) {
  return re(e, Z, Be);
}
function Le(e) {
  return v$1(e, function(t) {
    return t.isAttr;
  });
}
function He(e) {
  return v$1(e, function(t) {
    return !t.isAttr;
  });
}
function j(e) {
  this.tagName = e;
}
j.prototype.build = function(e) {
  return this.element = e, this;
};
j.prototype.serializeTo = function(e) {
  e.appendIndent().append("<" + this.tagName + ">" + this.element.id + "</" + this.tagName + ">").appendNewLine();
};
function R() {
}
R.prototype.serializeValue = R.prototype.serializeTo = function(e) {
  e.append(
    this.escape ? Ce(this.value) : this.value
  );
};
R.prototype.build = function(e, t) {
  return this.value = t, e.type === "String" && t.search(Z) !== -1 && (this.escape = true), this;
};
function G(e) {
  this.tagName = e;
}
ee(G, R);
G.prototype.serializeTo = function(e) {
  e.appendIndent().append("<" + this.tagName + ">"), this.serializeValue(e), e.append("</" + this.tagName + ">").appendNewLine();
};
function c(e, t) {
  this.body = [], this.attrs = [], this.parent = e, this.propertyDescriptor = t;
}
c.prototype.build = function(e) {
  this.element = e;
  var t = e.$descriptor, r = this.propertyDescriptor, n, i, a = t.isGeneric;
  return a ? n = this.parseGeneric(e) : n = this.parseNsAttributes(e), r ? this.ns = this.nsPropertyTagName(r) : this.ns = this.nsTagName(t), this.tagName = this.addTagName(this.ns), a || (i = ze(e), this.parseAttributes(Le(i)), this.parseContainments(He(i))), this.parseGenericAttributes(e, n), this;
};
c.prototype.nsTagName = function(e) {
  var t = this.logNamespaceUsed(e.ns);
  return Se(t, e);
};
c.prototype.nsPropertyTagName = function(e) {
  var t = this.logNamespaceUsed(e.ns);
  return Ue(t, e);
};
c.prototype.isLocalNs = function(e) {
  return e.uri === this.ns.uri;
};
c.prototype.nsAttributeName = function(e) {
  var t;
  if (S$1(e) ? t = u(e) : t = e.ns, e.inherited)
    return { localName: t.localName };
  var r = this.logNamespaceUsed(t);
  return this.getNamespaces().logUsed(r), this.isLocalNs(r) ? { localName: t.localName } : q$1({ localName: t.localName }, r);
};
c.prototype.parseGeneric = function(e) {
  var t = this, r = this.body, n = [];
  return o(e, function(i, a) {
    var s;
    a === "$body" ? r.push(new R().build({ type: "String" }, i)) : a === "$children" ? o(i, function(o2) {
      r.push(new c(t).build(o2));
    }) : a.indexOf("$") !== 0 && (s = t.parseNsAttribute(e, a, i), s && n.push({ name: a, value: i }));
  }), n;
};
c.prototype.parseNsAttribute = function(e, t, r) {
  var n = e.$model, i = u(t), a;
  if (i.prefix === "xmlns" && (a = { prefix: i.localName, uri: r }), !i.prefix && i.localName === "xmlns" && (a = { uri: r }), !a)
    return {
      name: t,
      value: r
    };
  if (n && n.getPackage(r))
    this.logNamespace(a, true, true);
  else {
    var s = this.logNamespaceUsed(a, true);
    this.getNamespaces().logUsed(s);
  }
};
c.prototype.parseNsAttributes = function(e, t) {
  var r = this, n = e.$attrs, i = [];
  return o(n, function(a, s) {
    var o2 = r.parseNsAttribute(e, s, a);
    o2 && i.push(o2);
  }), i;
};
c.prototype.parseGenericAttributes = function(e, t) {
  var r = this;
  o(t, function(n) {
    if (n.name !== C)
      try {
        r.addAttribute(r.nsAttributeName(n.name), n.value);
      } catch (i) {
        console.warn(
          "missing namespace information for ",
          n.name,
          "=",
          n.value,
          "on",
          e,
          i
        );
      }
  });
};
c.prototype.parseContainments = function(e) {
  var t = this, r = this.body, n = this.element;
  o(e, function(i) {
    var a = n.get(i.name), s = i.isReference, o$1 = i.isMany;
    if (o$1 || (a = [a]), i.isBody)
      r.push(new R().build(i, a[0]));
    else if (C$1(i.type))
      o(a, function(h) {
        r.push(new G(t.addTagName(t.nsPropertyTagName(i))).build(i, h));
      });
    else if (s)
      o(a, function(h) {
        r.push(new j(t.addTagName(t.nsPropertyTagName(i))).build(h));
      });
    else {
      var p = Y(i), l = ye(i);
      o(a, function(h) {
        var m;
        p ? m = new H(t, i) : l ? m = new c(t, i) : m = new c(t), r.push(m.build(h));
      });
    }
  });
};
c.prototype.getNamespaces = function(e) {
  var t = this.namespaces, r = this.parent, n;
  return t || (n = r && r.getNamespaces(), e || !n ? this.namespaces = t = new Te(n) : t = n), t;
};
c.prototype.logNamespace = function(e, t, r) {
  var n = this.getNamespaces(r), i = e.uri, a = e.prefix, s = n.byUri(i);
  return (!s || r) && n.add(e, t), n.mapPrefix(a, i), e;
};
c.prototype.logNamespaceUsed = function(e, t) {
  var r = this.element, n = r.$model, i = this.getNamespaces(t), a = e.prefix, s = e.uri, o2, p, l;
  if (!a && !s)
    return { localName: e.localName };
  if (l = me[a] || n && (n.getPackage(a) || {}).uri, s = s || l || i.uriByPrefix(a), !s)
    throw new Error("no namespace uri given for prefix <" + a + ">");
  if (e = i.byUri(s), !e) {
    for (o2 = a, p = 1; i.uriByPrefix(o2); )
      o2 = a + "_" + p++;
    e = this.logNamespace({ prefix: o2, uri: s }, l === s);
  }
  return a && i.mapPrefix(a, s), e;
};
c.prototype.parseAttributes = function(e) {
  var t = this, r = this.element;
  o(e, function(n) {
    var i = r.get(n.name);
    if (n.isReference)
      if (!n.isMany)
        i = i.id;
      else {
        var a = [];
        o(i, function(s) {
          a.push(s.id);
        }), i = a.join(" ");
      }
    t.addAttribute(t.nsAttributeName(n), i);
  });
};
c.prototype.addTagName = function(e) {
  var t = this.logNamespaceUsed(e);
  return this.getNamespaces().logUsed(t), te(e);
};
c.prototype.addAttribute = function(e, t) {
  var r = this.attrs;
  S$1(t) && (t = $e(t));
  var n = K$1(r, function(a) {
    return a.name.localName === e.localName && a.name.uri === e.uri && a.name.prefix === e.prefix;
  }), i = { name: e, value: t };
  n !== -1 ? r.splice(n, 1, i) : r.push(i);
};
c.prototype.serializeAttributes = function(e) {
  var t = this.attrs, r = this.namespaces;
  r && (t = Re(r).concat(t)), o(t, function(n) {
    e.append(" ").append(te(n.name)).append('="').append(n.value).append('"');
  });
};
c.prototype.serializeTo = function(e) {
  var t = this.body[0], r = t && t.constructor !== R;
  e.appendIndent().append("<" + this.tagName), this.serializeAttributes(e), e.append(t ? ">" : " />"), t && (r && e.appendNewLine().indent(), o(this.body, function(n) {
    n.serializeTo(e);
  }), r && e.unindent().appendIndent(), e.append("</" + this.tagName + ">")), e.appendNewLine();
};
function H(e, t) {
  c.call(this, e, t);
}
ee(H, c);
H.prototype.parseNsAttributes = function(e) {
  var t = c.prototype.parseNsAttributes.call(this, e), r = e.$descriptor;
  if (r.name === this.propertyDescriptor.type)
    return t;
  var n = this.typeNs = this.nsTagName(r);
  this.getNamespaces().logUsed(this.typeNs);
  var i = e.$model.getPackage(n.uri), a = i.xml && i.xml.typePrefix || "";
  return this.addAttribute(
    this.nsAttributeName(C),
    (n.prefix ? n.prefix + ":" : "") + a + r.ns.localName
  ), t;
};
H.prototype.isLocalNs = function(e) {
  return e.uri === (this.typeNs || this.ns).uri;
};
function Ie() {
  this.value = "", this.write = function(e) {
    this.value += e;
  };
}
function Oe(e, t) {
  var r = [""];
  this.append = function(n) {
    return e.write(n), this;
  }, this.appendNewLine = function() {
    return t && e.write(`
`), this;
  }, this.appendIndent = function() {
    return t && e.write(r.join("  ")), this;
  }, this.indent = function() {
    return r.push(""), this;
  }, this.unindent = function() {
    return r.pop(), this;
  };
}
function We(e) {
  e = q$1({ format: false, preamble: true }, e || {});
  function t(r, n) {
    var i = n || new Ie(), a = new Oe(i, e.format);
    if (e.preamble && a.append(we), new c().build(r).serializeTo(a), !n)
      return i.value;
  }
  return {
    toXML: t
  };
}
export {
  J as Reader,
  We as Writer
};
