import * as r from "lodash-es";
var m = "\0", u = "\0", c = "";
class p {
  constructor(e = {}) {
    this._isDirected = Object.prototype.hasOwnProperty.call(e, "directed") ? e.directed : !0, this._isMultigraph = Object.prototype.hasOwnProperty.call(e, "multigraph") ? e.multigraph : !1, this._isCompound = Object.prototype.hasOwnProperty.call(e, "compound") ? e.compound : !1, this._label = void 0, this._defaultNodeLabelFn = r.constant(void 0), this._defaultEdgeLabelFn = r.constant(void 0), this._nodes = {}, this._isCompound && (this._parent = {}, this._children = {}, this._children[u] = {}), this._in = {}, this._preds = {}, this._out = {}, this._sucs = {}, this._edgeObjs = {}, this._edgeLabels = {};
  }
  /* === Graph functions ========= */
  isDirected() {
    return this._isDirected;
  }
  isMultigraph() {
    return this._isMultigraph;
  }
  isCompound() {
    return this._isCompound;
  }
  setGraph(e) {
    return this._label = e, this;
  }
  graph() {
    return this._label;
  }
  /* === Node functions ========== */
  setDefaultNodeLabel(e) {
    return r.isFunction(e) || (e = r.constant(e)), this._defaultNodeLabelFn = e, this;
  }
  nodeCount() {
    return this._nodeCount;
  }
  nodes() {
    return r.keys(this._nodes);
  }
  sources() {
    var e = this;
    return r.filter(this.nodes(), function(t) {
      return r.isEmpty(e._in[t]);
    });
  }
  sinks() {
    var e = this;
    return r.filter(this.nodes(), function(t) {
      return r.isEmpty(e._out[t]);
    });
  }
  setNodes(e, t) {
    var s = arguments, i = this;
    return r.each(e, function(n) {
      s.length > 1 ? i.setNode(n, t) : i.setNode(n);
    }), this;
  }
  setNode(e, t) {
    return Object.prototype.hasOwnProperty.call(this._nodes, e) ? (arguments.length > 1 && (this._nodes[e] = t), this) : (this._nodes[e] = arguments.length > 1 ? t : this._defaultNodeLabelFn(e), this._isCompound && (this._parent[e] = u, this._children[e] = {}, this._children[u][e] = !0), this._in[e] = {}, this._preds[e] = {}, this._out[e] = {}, this._sucs[e] = {}, ++this._nodeCount, this);
  }
  node(e) {
    return this._nodes[e];
  }
  hasNode(e) {
    return Object.prototype.hasOwnProperty.call(this._nodes, e);
  }
  removeNode(e) {
    if (Object.prototype.hasOwnProperty.call(this._nodes, e)) {
      var t = (s) => this.removeEdge(this._edgeObjs[s]);
      delete this._nodes[e], this._isCompound && (this._removeFromParentsChildList(e), delete this._parent[e], r.each(this.children(e), (s) => {
        this.setParent(s);
      }), delete this._children[e]), r.each(r.keys(this._in[e]), t), delete this._in[e], delete this._preds[e], r.each(r.keys(this._out[e]), t), delete this._out[e], delete this._sucs[e], --this._nodeCount;
    }
    return this;
  }
  setParent(e, t) {
    if (!this._isCompound)
      throw new Error("Cannot set parent in a non-compound graph");
    if (r.isUndefined(t))
      t = u;
    else {
      t += "";
      for (var s = t; !r.isUndefined(s); s = this.parent(s))
        if (s === e)
          throw new Error("Setting " + t + " as parent of " + e + " would create a cycle");
      this.setNode(t);
    }
    return this.setNode(e), this._removeFromParentsChildList(e), this._parent[e] = t, this._children[t][e] = !0, this;
  }
  _removeFromParentsChildList(e) {
    delete this._children[this._parent[e]][e];
  }
  parent(e) {
    if (this._isCompound) {
      var t = this._parent[e];
      if (t !== u)
        return t;
    }
  }
  children(e) {
    if (r.isUndefined(e) && (e = u), this._isCompound) {
      var t = this._children[e];
      if (t)
        return r.keys(t);
    } else {
      if (e === u)
        return this.nodes();
      if (this.hasNode(e))
        return [];
    }
  }
  predecessors(e) {
    var t = this._preds[e];
    if (t)
      return r.keys(t);
  }
  successors(e) {
    var t = this._sucs[e];
    if (t)
      return r.keys(t);
  }
  neighbors(e) {
    var t = this.predecessors(e);
    if (t)
      return r.union(t, this.successors(e));
  }
  isLeaf(e) {
    var t;
    return this.isDirected() ? t = this.successors(e) : t = this.neighbors(e), t.length === 0;
  }
  filterNodes(e) {
    var t = new this.constructor({
      directed: this._isDirected,
      multigraph: this._isMultigraph,
      compound: this._isCompound
    });
    t.setGraph(this.graph());
    var s = this;
    r.each(this._nodes, function(h, d) {
      e(d) && t.setNode(d, h);
    }), r.each(this._edgeObjs, function(h) {
      t.hasNode(h.v) && t.hasNode(h.w) && t.setEdge(h, s.edge(h));
    });
    var i = {};
    function n(h) {
      var d = s.parent(h);
      return d === void 0 || t.hasNode(d) ? (i[h] = d, d) : d in i ? i[d] : n(d);
    }
    return this._isCompound && r.each(t.nodes(), function(h) {
      t.setParent(h, n(h));
    }), t;
  }
  /* === Edge functions ========== */
  setDefaultEdgeLabel(e) {
    return r.isFunction(e) || (e = r.constant(e)), this._defaultEdgeLabelFn = e, this;
  }
  edgeCount() {
    return this._edgeCount;
  }
  edges() {
    return r.values(this._edgeObjs);
  }
  setPath(e, t) {
    var s = this, i = arguments;
    return r.reduce(e, function(n, h) {
      return i.length > 1 ? s.setEdge(n, h, t) : s.setEdge(n, h), h;
    }), this;
  }
  /*
   * setEdge(v, w, [value, [name]])
   * setEdge({ v, w, [name] }, [value])
   */
  setEdge() {
    var e, t, s, i, n = !1, h = arguments[0];
    typeof h == "object" && h !== null && "v" in h ? (e = h.v, t = h.w, s = h.name, arguments.length === 2 && (i = arguments[1], n = !0)) : (e = h, t = arguments[1], s = arguments[3], arguments.length > 2 && (i = arguments[2], n = !0)), e = "" + e, t = "" + t, r.isUndefined(s) || (s = "" + s);
    var d = _(this._isDirected, e, t, s);
    if (Object.prototype.hasOwnProperty.call(this._edgeLabels, d))
      return n && (this._edgeLabels[d] = i), this;
    if (!r.isUndefined(s) && !this._isMultigraph)
      throw new Error("Cannot set a named edge when isMultigraph = false");
    this.setNode(e), this.setNode(t), this._edgeLabels[d] = n ? i : this._defaultEdgeLabelFn(e, t, s);
    var a = b(this._isDirected, e, t, s);
    return e = a.v, t = a.w, Object.freeze(a), this._edgeObjs[d] = a, f(this._preds[t], e), f(this._sucs[e], t), this._in[t][d] = a, this._out[e][d] = a, this._edgeCount++, this;
  }
  edge(e, t, s) {
    var i = arguments.length === 1 ? l(this._isDirected, arguments[0]) : _(this._isDirected, e, t, s);
    return this._edgeLabels[i];
  }
  hasEdge(e, t, s) {
    var i = arguments.length === 1 ? l(this._isDirected, arguments[0]) : _(this._isDirected, e, t, s);
    return Object.prototype.hasOwnProperty.call(this._edgeLabels, i);
  }
  removeEdge(e, t, s) {
    var i = arguments.length === 1 ? l(this._isDirected, arguments[0]) : _(this._isDirected, e, t, s), n = this._edgeObjs[i];
    return n && (e = n.v, t = n.w, delete this._edgeLabels[i], delete this._edgeObjs[i], g(this._preds[t], e), g(this._sucs[e], t), delete this._in[t][i], delete this._out[e][i], this._edgeCount--), this;
  }
  inEdges(e, t) {
    var s = this._in[e];
    if (s) {
      var i = r.values(s);
      return t ? r.filter(i, function(n) {
        return n.v === t;
      }) : i;
    }
  }
  outEdges(e, t) {
    var s = this._out[e];
    if (s) {
      var i = r.values(s);
      return t ? r.filter(i, function(n) {
        return n.w === t;
      }) : i;
    }
  }
  nodeEdges(e, t) {
    var s = this.inEdges(e, t);
    if (s)
      return s.concat(this.outEdges(e, t));
  }
}
p.prototype._nodeCount = 0;
p.prototype._edgeCount = 0;
function f(o, e) {
  o[e] ? o[e]++ : o[e] = 1;
}
function g(o, e) {
  --o[e] || delete o[e];
}
function _(o, e, t, s) {
  var i = "" + e, n = "" + t;
  if (!o && i > n) {
    var h = i;
    i = n, n = h;
  }
  return i + c + n + c + (r.isUndefined(s) ? m : s);
}
function b(o, e, t, s) {
  var i = "" + e, n = "" + t;
  if (!o && i > n) {
    var h = i;
    i = n, n = h;
  }
  var d = { v: i, w: n };
  return s && (d.name = s), d;
}
function l(o, e) {
  return _(o, e.v, e.w, e.name);
}
export {
  p as G
};
