import forEach_default from "../../../../lodash-es/forEach.js";
import filter_default from "../../../../lodash-es/filter.js";
import find_default from "../../../../lodash-es/find.js";
import minBy_default from "../../../../lodash-es/minBy.js";
import { simplify } from "../util.js";
import { longestPath, slack } from "./util.js";
import { feasibleTree } from "./feasible-tree.js";
import { postorder } from "../../graphlib/alg/postorder.js";
import { preorder } from "../../graphlib/alg/preorder.js";
import "../../graphlib/alg/index.js";
networkSimplex.initLowLimValues = initLowLimValues, networkSimplex.initCutValues = initCutValues, networkSimplex.calcCutValue = calcCutValue, networkSimplex.leaveEdge = leaveEdge, networkSimplex.enterEdge = enterEdge, networkSimplex.exchangeEdges = exchangeEdges;
function networkSimplex(e) {
	e = simplify(e), longestPath(e);
	var d = feasibleTree(e);
	initLowLimValues(d), initCutValues(d, e);
	for (var f, p; f = leaveEdge(d);) p = enterEdge(d, e, f), exchangeEdges(d, e, f, p);
}
function initCutValues(d, f) {
	var p = postorder(d, d.nodes());
	p = p.slice(0, p.length - 1), forEach_default(p, function(e) {
		assignCutValue(d, f, e);
	});
}
function assignCutValue(e, d, f) {
	var p = e.node(f).parent;
	e.edge(f, p).cutvalue = calcCutValue(e, d, f);
}
function calcCutValue(d, f, p) {
	var m = d.node(p).parent, h = !0, g = f.edge(p, m), _ = 0;
	return g ||= (h = !1, f.edge(m, p)), _ = g.weight, forEach_default(f.nodeEdges(p), function(e) {
		var g = e.v === p, v = g ? e.w : e.v;
		if (v !== m) {
			var y = g === h, b = f.edge(e).weight;
			if (_ += y ? b : -b, isTreeEdge(d, p, v)) {
				var x = d.edge(p, v).cutvalue;
				_ += y ? -x : x;
			}
		}
	}), _;
}
function initLowLimValues(e, d) {
	arguments.length < 2 && (d = e.nodes()[0]), dfsAssignLowLim(e, {}, 1, d);
}
function dfsAssignLowLim(d, f, p, m, h) {
	var g = p, _ = d.node(m);
	return f[m] = !0, forEach_default(d.neighbors(m), function(e) {
		Object.prototype.hasOwnProperty.call(f, e) || (p = dfsAssignLowLim(d, f, p, e, m));
	}), _.low = g, _.lim = p++, h ? _.parent = h : delete _.parent, p;
}
function leaveEdge(e) {
	return find_default(e.edges(), function(d) {
		return e.edge(d).cutvalue < 0;
	});
}
function enterEdge(e, f, m) {
	var h = m.v, _ = m.w;
	f.hasEdge(h, _) || (h = m.w, _ = m.v);
	var v = e.node(h), y = e.node(_), b = v, x = !1;
	return v.lim > y.lim && (b = y, x = !0), minBy_default(filter_default(f.edges(), function(d) {
		return x === isDescendant(e, e.node(d.v), b) && x !== isDescendant(e, e.node(d.w), b);
	}), function(e) {
		return slack(f, e);
	});
}
function exchangeEdges(e, d, f, p) {
	var m = f.v, h = f.w;
	e.removeEdge(m, h), e.setEdge(p.v, p.w, {}), initLowLimValues(e), initCutValues(e, d), updateRanks(e, d);
}
function updateRanks(d, p) {
	var m = preorder(d, find_default(d.nodes(), function(e) {
		return !p.node(e).parent;
	}));
	m = m.slice(1), forEach_default(m, function(e) {
		var f = d.node(e).parent, m = p.edge(e, f), h = !1;
		m || (m = p.edge(f, e), h = !0), p.node(e).rank = p.node(f).rank + (h ? m.minlen : -m.minlen);
	});
}
function isTreeEdge(e, d, f) {
	return e.hasEdge(d, f);
}
function isDescendant(e, d, f) {
	return f.low <= d.lim && d.lim <= f.lim;
}
export { networkSimplex };
