import isFunction_default from "../../../lodash-es/isFunction.js";
import constant_default from "../../../lodash-es/constant.js";
import isEmpty_default from "../../../lodash-es/isEmpty.js";
import keys_default from "../../../lodash-es/keys.js";
import forEach_default from "../../../lodash-es/forEach.js";
import filter_default from "../../../lodash-es/filter.js";
import values_default from "../../../lodash-es/values.js";
import isUndefined_default from "../../../lodash-es/isUndefined.js";
import reduce_default from "../../../lodash-es/reduce.js";
import union_default from "../../../lodash-es/union.js";
var DEFAULT_EDGE_NAME = "\0", GRAPH_NODE = "\0", EDGE_KEY_DELIM = "", Graph = class {
	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 = constant_default(void 0), this._defaultEdgeLabelFn = constant_default(void 0), this._nodes = {}, this._isCompound && (this._parent = {}, this._children = {}, this._children[GRAPH_NODE] = {}), this._in = {}, this._preds = {}, this._out = {}, this._sucs = {}, this._edgeObjs = {}, this._edgeLabels = {};
	}
	isDirected() {
		return this._isDirected;
	}
	isMultigraph() {
		return this._isMultigraph;
	}
	isCompound() {
		return this._isCompound;
	}
	setGraph(e) {
		return this._label = e, this;
	}
	graph() {
		return this._label;
	}
	setDefaultNodeLabel(f) {
		return isFunction_default(f) || (f = constant_default(f)), this._defaultNodeLabelFn = f, this;
	}
	nodeCount() {
		return this._nodeCount;
	}
	nodes() {
		return keys_default(this._nodes);
	}
	sources() {
		var e = this;
		return filter_default(this.nodes(), function(d) {
			return isEmpty_default(e._in[d]);
		});
	}
	sinks() {
		var e = this;
		return filter_default(this.nodes(), function(d) {
			return isEmpty_default(e._out[d]);
		});
	}
	setNodes(e, d) {
		var f = arguments, p = this;
		return forEach_default(e, function(e) {
			f.length > 1 ? p.setNode(e, d) : p.setNode(e);
		}), this;
	}
	setNode(e, d) {
		return Object.prototype.hasOwnProperty.call(this._nodes, e) ? (arguments.length > 1 && (this._nodes[e] = d), this) : (this._nodes[e] = arguments.length > 1 ? d : this._defaultNodeLabelFn(e), this._isCompound && (this._parent[e] = GRAPH_NODE, this._children[e] = {}, this._children[GRAPH_NODE][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 d = (e) => this.removeEdge(this._edgeObjs[e]);
			delete this._nodes[e], this._isCompound && (this._removeFromParentsChildList(e), delete this._parent[e], forEach_default(this.children(e), (e) => {
				this.setParent(e);
			}), delete this._children[e]), forEach_default(keys_default(this._in[e]), d), delete this._in[e], delete this._preds[e], forEach_default(keys_default(this._out[e]), d), delete this._out[e], delete this._sucs[e], --this._nodeCount;
		}
		return this;
	}
	setParent(e, d) {
		if (!this._isCompound) throw Error("Cannot set parent in a non-compound graph");
		if (isUndefined_default(d)) d = GRAPH_NODE;
		else {
			d += "";
			for (var f = d; !isUndefined_default(f); f = this.parent(f)) if (f === e) throw Error("Setting " + d + " as parent of " + e + " would create a cycle");
			this.setNode(d);
		}
		return this.setNode(e), this._removeFromParentsChildList(e), this._parent[e] = d, this._children[d][e] = !0, this;
	}
	_removeFromParentsChildList(e) {
		delete this._children[this._parent[e]][e];
	}
	parent(e) {
		if (this._isCompound) {
			var d = this._parent[e];
			if (d !== GRAPH_NODE) return d;
		}
	}
	children(e) {
		if (isUndefined_default(e) && (e = GRAPH_NODE), this._isCompound) {
			var d = this._children[e];
			if (d) return keys_default(d);
		} else if (e === GRAPH_NODE) return this.nodes();
		else if (this.hasNode(e)) return [];
	}
	predecessors(e) {
		var d = this._preds[e];
		if (d) return keys_default(d);
	}
	successors(e) {
		var d = this._sucs[e];
		if (d) return keys_default(d);
	}
	neighbors(e) {
		var d = this.predecessors(e);
		if (d) return union_default(d, this.successors(e));
	}
	isLeaf(e) {
		return (this.isDirected() ? this.successors(e) : this.neighbors(e)).length === 0;
	}
	filterNodes(e) {
		var d = new this.constructor({
			directed: this._isDirected,
			multigraph: this._isMultigraph,
			compound: this._isCompound
		});
		d.setGraph(this.graph());
		var f = this;
		forEach_default(this._nodes, function(f, p) {
			e(p) && d.setNode(p, f);
		}), forEach_default(this._edgeObjs, function(e) {
			d.hasNode(e.v) && d.hasNode(e.w) && d.setEdge(e, f.edge(e));
		});
		var p = {};
		function h(e) {
			var m = f.parent(e);
			return m === void 0 || d.hasNode(m) ? (p[e] = m, m) : m in p ? p[m] : h(m);
		}
		return this._isCompound && forEach_default(d.nodes(), function(e) {
			d.setParent(e, h(e));
		}), d;
	}
	setDefaultEdgeLabel(f) {
		return isFunction_default(f) || (f = constant_default(f)), this._defaultEdgeLabelFn = f, this;
	}
	edgeCount() {
		return this._edgeCount;
	}
	edges() {
		return values_default(this._edgeObjs);
	}
	setPath(e, d) {
		var f = this, p = arguments;
		return reduce_default(e, function(e, m) {
			return p.length > 1 ? f.setEdge(e, m, d) : f.setEdge(e, m), m;
		}), this;
	}
	setEdge() {
		var e, d, f, p, m = !1, h = arguments[0];
		typeof h == "object" && h && "v" in h ? (e = h.v, d = h.w, f = h.name, arguments.length === 2 && (p = arguments[1], m = !0)) : (e = h, d = arguments[1], f = arguments[3], arguments.length > 2 && (p = arguments[2], m = !0)), e = "" + e, d = "" + d, isUndefined_default(f) || (f = "" + f);
		var g = edgeArgsToId(this._isDirected, e, d, f);
		if (Object.prototype.hasOwnProperty.call(this._edgeLabels, g)) return m && (this._edgeLabels[g] = p), this;
		if (!isUndefined_default(f) && !this._isMultigraph) throw Error("Cannot set a named edge when isMultigraph = false");
		this.setNode(e), this.setNode(d), this._edgeLabels[g] = m ? p : this._defaultEdgeLabelFn(e, d, f);
		var v = edgeArgsToObj(this._isDirected, e, d, f);
		return e = v.v, d = v.w, Object.freeze(v), this._edgeObjs[g] = v, incrementOrInitEntry(this._preds[d], e), incrementOrInitEntry(this._sucs[e], d), this._in[d][g] = v, this._out[e][g] = v, this._edgeCount++, this;
	}
	edge(e, d, f) {
		var p = arguments.length === 1 ? edgeObjToId(this._isDirected, arguments[0]) : edgeArgsToId(this._isDirected, e, d, f);
		return this._edgeLabels[p];
	}
	hasEdge(e, d, f) {
		var p = arguments.length === 1 ? edgeObjToId(this._isDirected, arguments[0]) : edgeArgsToId(this._isDirected, e, d, f);
		return Object.prototype.hasOwnProperty.call(this._edgeLabels, p);
	}
	removeEdge(e, d, f) {
		var p = arguments.length === 1 ? edgeObjToId(this._isDirected, arguments[0]) : edgeArgsToId(this._isDirected, e, d, f), m = this._edgeObjs[p];
		return m && (e = m.v, d = m.w, delete this._edgeLabels[p], delete this._edgeObjs[p], decrementOrRemoveEntry(this._preds[d], e), decrementOrRemoveEntry(this._sucs[e], d), delete this._in[d][p], delete this._out[e][p], this._edgeCount--), this;
	}
	inEdges(e, d) {
		var f = this._in[e];
		if (f) {
			var p = values_default(f);
			return d ? filter_default(p, function(e) {
				return e.v === d;
			}) : p;
		}
	}
	outEdges(e, d) {
		var f = this._out[e];
		if (f) {
			var p = values_default(f);
			return d ? filter_default(p, function(e) {
				return e.w === d;
			}) : p;
		}
	}
	nodeEdges(e, d) {
		var f = this.inEdges(e, d);
		if (f) return f.concat(this.outEdges(e, d));
	}
};
Graph.prototype._nodeCount = 0, Graph.prototype._edgeCount = 0;
function incrementOrInitEntry(e, d) {
	e[d] ? e[d]++ : e[d] = 1;
}
function decrementOrRemoveEntry(e, d) {
	--e[d] || delete e[d];
}
function edgeArgsToId(e, d, f, p) {
	var m = "" + d, h = "" + f;
	if (!e && m > h) {
		var g = m;
		m = h, h = g;
	}
	return m + EDGE_KEY_DELIM + h + EDGE_KEY_DELIM + (isUndefined_default(p) ? DEFAULT_EDGE_NAME : p);
}
function edgeArgsToObj(e, d, f, p) {
	var m = "" + d, h = "" + f;
	if (!e && m > h) {
		var g = m;
		m = h, h = g;
	}
	var _ = {
		v: m,
		w: h
	};
	return p && (_.name = p), _;
}
function edgeObjToId(e, d) {
	return edgeArgsToId(e, d.v, d.w, d.name);
}
export { Graph };
