import merge_default from "../../../lodash-es/merge.js";
import defaults_default from "../../../lodash-es/defaults.js";
import last_default from "../../../lodash-es/last.js";
import forEach_default from "../../../lodash-es/forEach.js";
import mapValues_default from "../../../lodash-es/mapValues.js";
import max_default from "../../../lodash-es/max.js";
import pick_default from "../../../lodash-es/pick.js";
import { Graph } from "../graphlib/graph.js";
import "../graphlib/index.js";
import { run, undo } from "./acyclic.js";
import { addDummyNode, asNonCompoundGraph, buildLayerMatrix, intersectRect, normalizeRanks, notime, removeEmptyRanks, time } from "./util.js";
import { addBorderSegments } from "./add-border-segments.js";
import { adjust, undo as undo$1 } from "./coordinate-system.js";
import { run as run$1, undo as undo$2 } from "./normalize.js";
import { rank } from "./rank/index.js";
import { cleanup, run as run$2 } from "./nesting-graph.js";
import { order } from "./order/index.js";
import { parentDummyChains } from "./parent-dummy-chains.js";
import { position } from "./position/index.js";
function layout(g, G) {
	var K = G && G.debugTiming ? time : notime;
	K("layout", () => {
		var G = K("  buildLayoutGraph", () => buildLayoutGraph(g));
		K("  runLayout", () => runLayout(G, K)), K("  updateInputGraph", () => updateInputGraph(g, G));
	});
}
function runLayout(g, G) {
	G("    makeSpaceForEdgeLabels", () => makeSpaceForEdgeLabels(g)), G("    removeSelfEdges", () => removeSelfEdges(g)), G("    acyclic", () => run(g)), G("    nestingGraph.run", () => run$2(g)), G("    rank", () => rank(asNonCompoundGraph(g))), G("    injectEdgeLabelProxies", () => injectEdgeLabelProxies(g)), G("    removeEmptyRanks", () => removeEmptyRanks(g)), G("    nestingGraph.cleanup", () => cleanup(g)), G("    normalizeRanks", () => normalizeRanks(g)), G("    assignRankMinMax", () => assignRankMinMax(g)), G("    removeEdgeLabelProxies", () => removeEdgeLabelProxies(g)), G("    normalize.run", () => run$1(g)), G("    parentDummyChains", () => parentDummyChains(g)), G("    addBorderSegments", () => addBorderSegments(g)), G("    order", () => order(g)), G("    insertSelfEdges", () => insertSelfEdges(g)), G("    adjustCoordinateSystem", () => adjust(g)), G("    position", () => position(g)), G("    positionSelfEdges", () => positionSelfEdges(g)), G("    removeBorderNodes", () => removeBorderNodes(g)), G("    normalize.undo", () => undo$2(g)), G("    fixupEdgeLabelCoords", () => fixupEdgeLabelCoords(g)), G("    undoCoordinateSystem", () => undo$1(g)), G("    translateGraph", () => translateGraph(g)), G("    assignNodeIntersects", () => assignNodeIntersects(g)), G("    reversePoints", () => reversePointsForReversedEdges(g)), G("    acyclic.undo", () => undo(g));
}
function updateInputGraph(g, G) {
	forEach_default(g.nodes(), function(K) {
		var q = g.node(K), J = G.node(K);
		q && (q.x = J.x, q.y = J.y, G.children(K).length && (q.width = J.width, q.height = J.height));
	}), forEach_default(g.edges(), function(K) {
		var q = g.edge(K), J = G.edge(K);
		q.points = J.points, Object.prototype.hasOwnProperty.call(J, "x") && (q.x = J.x, q.y = J.y);
	}), g.graph().width = G.graph().width, g.graph().height = G.graph().height;
}
var graphNumAttrs = [
	"nodesep",
	"edgesep",
	"ranksep",
	"marginx",
	"marginy"
], graphDefaults = {
	ranksep: 50,
	edgesep: 20,
	nodesep: 50,
	rankdir: "tb"
}, graphAttrs = [
	"acyclicer",
	"ranker",
	"rankdir",
	"align"
], nodeNumAttrs = ["width", "height"], nodeDefaults = {
	width: 0,
	height: 0
}, edgeNumAttrs = [
	"minlen",
	"weight",
	"width",
	"height",
	"labeloffset"
], edgeDefaults = {
	minlen: 1,
	weight: 1,
	width: 0,
	height: 0,
	labeloffset: 10,
	labelpos: "r"
}, edgeAttrs = ["labelpos"];
function buildLayoutGraph(K) {
	var J = new Graph({
		multigraph: !0,
		compound: !0
	}), Y = canonicalize(K.graph());
	return J.setGraph(merge_default({}, graphDefaults, selectNumberAttrs(Y, graphNumAttrs), pick_default(Y, graphAttrs))), forEach_default(K.nodes(), function(g) {
		var q = canonicalize(K.node(g));
		J.setNode(g, defaults_default(selectNumberAttrs(q, nodeNumAttrs), nodeDefaults)), J.setParent(g, K.parent(g));
	}), forEach_default(K.edges(), function(G) {
		var q = canonicalize(K.edge(G));
		J.setEdge(G, merge_default({}, edgeDefaults, selectNumberAttrs(q, edgeNumAttrs), pick_default(q, edgeAttrs)));
	}), J;
}
function makeSpaceForEdgeLabels(g) {
	var G = g.graph();
	G.ranksep /= 2, forEach_default(g.edges(), function(K) {
		var q = g.edge(K);
		q.minlen *= 2, q.labelpos.toLowerCase() !== "c" && (G.rankdir === "TB" || G.rankdir === "BT" ? q.width += q.labeloffset : q.height += q.labeloffset);
	});
}
function injectEdgeLabelProxies(g) {
	forEach_default(g.edges(), function(G) {
		var K = g.edge(G);
		if (K.width && K.height) {
			var q = g.node(G.v);
			addDummyNode(g, "edge-proxy", {
				rank: (g.node(G.w).rank - q.rank) / 2 + q.rank,
				e: G
			}, "_ep");
		}
	});
}
function assignRankMinMax(g) {
	var G = 0;
	forEach_default(g.nodes(), function(K) {
		var q = g.node(K);
		q.borderTop && (q.minRank = g.node(q.borderTop).rank, q.maxRank = g.node(q.borderBottom).rank, G = max_default(G, q.maxRank));
	}), g.graph().maxRank = G;
}
function removeEdgeLabelProxies(g) {
	forEach_default(g.nodes(), function(G) {
		var K = g.node(G);
		K.dummy === "edge-proxy" && (g.edge(K.e).labelRank = K.rank, g.removeNode(G));
	});
}
function translateGraph(g) {
	var G = Infinity, K = 0, J = Infinity, Y = 0, X = g.graph(), Z = X.marginx || 0, Q = X.marginy || 0;
	function $(g) {
		var q = g.x, X = g.y, Z = g.width, Q = g.height;
		G = Math.min(G, q - Z / 2), K = Math.max(K, q + Z / 2), J = Math.min(J, X - Q / 2), Y = Math.max(Y, X + Q / 2);
	}
	forEach_default(g.nodes(), function(G) {
		$(g.node(G));
	}), forEach_default(g.edges(), function(G) {
		var K = g.edge(G);
		Object.prototype.hasOwnProperty.call(K, "x") && $(K);
	}), G -= Z, J -= Q, forEach_default(g.nodes(), function(K) {
		var q = g.node(K);
		q.x -= G, q.y -= J;
	}), forEach_default(g.edges(), function(K) {
		var Y = g.edge(K);
		forEach_default(Y.points, function(g) {
			g.x -= G, g.y -= J;
		}), Object.prototype.hasOwnProperty.call(Y, "x") && (Y.x -= G), Object.prototype.hasOwnProperty.call(Y, "y") && (Y.y -= J);
	}), X.width = K - G + Z, X.height = Y - J + Q;
}
function assignNodeIntersects(g) {
	forEach_default(g.edges(), function(G) {
		var K = g.edge(G), q = g.node(G.v), J = g.node(G.w), Y, X;
		K.points ? (Y = K.points[0], X = K.points[K.points.length - 1]) : (K.points = [], Y = J, X = q), K.points.unshift(intersectRect(q, Y)), K.points.push(intersectRect(J, X));
	});
}
function fixupEdgeLabelCoords(g) {
	forEach_default(g.edges(), function(G) {
		var K = g.edge(G);
		if (Object.prototype.hasOwnProperty.call(K, "x")) switch ((K.labelpos === "l" || K.labelpos === "r") && (K.width -= K.labeloffset), K.labelpos) {
			case "l":
				K.x -= K.width / 2 + K.labeloffset;
				break;
			case "r":
				K.x += K.width / 2 + K.labeloffset;
				break;
		}
	});
}
function reversePointsForReversedEdges(g) {
	forEach_default(g.edges(), function(G) {
		var K = g.edge(G);
		K.reversed && K.points.reverse();
	});
}
function removeBorderNodes(g) {
	forEach_default(g.nodes(), function(G) {
		if (g.children(G).length) {
			var q = g.node(G), J = g.node(q.borderTop), Y = g.node(q.borderBottom), X = g.node(last_default(q.borderLeft)), Z = g.node(last_default(q.borderRight));
			q.width = Math.abs(Z.x - X.x), q.height = Math.abs(Y.y - J.y), q.x = X.x + q.width / 2, q.y = J.y + q.height / 2;
		}
	}), forEach_default(g.nodes(), function(G) {
		g.node(G).dummy === "border" && g.removeNode(G);
	});
}
function removeSelfEdges(g) {
	forEach_default(g.edges(), function(G) {
		if (G.v === G.w) {
			var K = g.node(G.v);
			K.selfEdges ||= [], K.selfEdges.push({
				e: G,
				label: g.edge(G)
			}), g.removeEdge(G);
		}
	});
}
function insertSelfEdges(g) {
	forEach_default(buildLayerMatrix(g), function(G) {
		var K = 0;
		forEach_default(G, function(G, J) {
			var Y = g.node(G);
			Y.order = J + K, forEach_default(Y.selfEdges, function(G) {
				addDummyNode(g, "selfedge", {
					width: G.label.width,
					height: G.label.height,
					rank: Y.rank,
					order: J + ++K,
					e: G.e,
					label: G.label
				}, "_se");
			}), delete Y.selfEdges;
		});
	});
}
function positionSelfEdges(g) {
	forEach_default(g.nodes(), function(G) {
		var K = g.node(G);
		if (K.dummy === "selfedge") {
			var q = g.node(K.e.v), J = q.x + q.width / 2, Y = q.y, X = K.x - J, Z = q.height / 2;
			g.setEdge(K.e, K.label), g.removeNode(G), K.label.points = [
				{
					x: J + 2 * X / 3,
					y: Y - Z
				},
				{
					x: J + 5 * X / 6,
					y: Y - Z
				},
				{
					x: J + X,
					y: Y
				},
				{
					x: J + 5 * X / 6,
					y: Y + Z
				},
				{
					x: J + 2 * X / 3,
					y: Y + Z
				}
			], K.label.x = K.x, K.label.y = K.y;
		}
	});
}
function selectNumberAttrs(g, G) {
	return mapValues_default(pick_default(g, G), Number);
}
function canonicalize(g) {
	var G = {};
	return forEach_default(g, function(g, K) {
		G[K.toLowerCase()] = g;
	}), G;
}
export { layout };
