import { n as e, t } from "../../utils-C_mWfcFX.js";
//#region src/visualization/flow-diagram/index.ts
var n = "http://www.w3.org/2000/svg", r = 140, i = 50, a = 100, o = 180, s = 60, c = 8, l = class {
	el;
	diagramId;
	direction;
	zoomable;
	pannable;
	onNodeClick;
	onEdgeClick;
	svg;
	mainGroup;
	defsEl;
	nodes;
	edges;
	layoutNodes = [];
	selectedNodeId = null;
	viewBox;
	isPanning = !1;
	panStart = {
		x: 0,
		y: 0
	};
	panOrigin = {
		x: 0,
		y: 0
	};
	boundWheel;
	boundMouseDown;
	boundMouseMove;
	boundMouseUp;
	constructor(r) {
		this.diagramId = e("cmm-flow-diagram"), this.direction = r.direction ?? "TB", this.zoomable = r.zoomable !== !1, this.pannable = r.pannable !== !1, this.onNodeClick = r.onNodeClick, this.onEdgeClick = r.onEdgeClick, this.nodes = [...r.nodes], this.edges = [...r.edges], this.viewBox = {
			x: 0,
			y: 0,
			w: 800,
			h: 600
		}, this.el = document.createElement("div"), this.el.id = this.diagramId, this.el.className = this.buildClassName(r.className), this.svg = document.createElementNS(n, "svg"), this.svg.classList.add("cmm-flow-diagram__svg"), this.defsEl = document.createElementNS(n, "defs"), this.svg.appendChild(this.defsEl), this.mainGroup = document.createElementNS(n, "g"), this.svg.appendChild(this.mainGroup), this.el.appendChild(this.svg), this.createArrowMarker(), t(r.container).appendChild(this.el);
		let i = this.el.getBoundingClientRect();
		i.width > 0 && i.height > 0 && (this.viewBox.w = i.width, this.viewBox.h = i.height), this.boundWheel = (e) => {
			this.handleWheel(e);
		}, this.boundMouseDown = (e) => {
			this.handleMouseDown(e);
		}, this.boundMouseMove = (e) => {
			this.handleMouseMove(e);
		}, this.boundMouseUp = () => {
			this.handleMouseUp();
		}, this.zoomable && this.el.addEventListener("wheel", this.boundWheel, { passive: !1 }), this.pannable && (this.el.addEventListener("mousedown", this.boundMouseDown), document.addEventListener("mousemove", this.boundMouseMove), document.addEventListener("mouseup", this.boundMouseUp)), this.render(), this.zoomToFit();
	}
	update(e, t) {
		this.nodes = [...e], this.edges = [...t], this.selectedNodeId = null, this.render(), this.zoomToFit();
	}
	zoomToFit() {
		if (this.layoutNodes.length === 0) return;
		let e = Infinity, t = Infinity, n = -Infinity, r = -Infinity;
		for (let i of this.layoutNodes) i.x < e && (e = i.x), i.y < t && (t = i.y), i.x + i.width > n && (n = i.x + i.width), i.y + i.height > r && (r = i.y + i.height);
		this.viewBox = {
			x: e - 40,
			y: t - 40,
			w: n - e + 80,
			h: r - t + 80
		}, this.applyViewBox();
	}
	destroy() {
		this.zoomable && this.el.removeEventListener("wheel", this.boundWheel), this.pannable && (this.el.removeEventListener("mousedown", this.boundMouseDown), document.removeEventListener("mousemove", this.boundMouseMove), document.removeEventListener("mouseup", this.boundMouseUp)), this.el.remove();
	}
	computeLayout() {
		if (this.nodes.every((e) => e.x !== void 0 && e.y !== void 0)) {
			this.layoutNodes = this.nodes.map((e) => ({
				id: e.id,
				label: e.label,
				type: e.type ?? "process",
				x: e.x ?? 0,
				y: e.y ?? 0,
				width: e.width ?? r,
				height: e.height ?? i,
				color: e.color,
				icon: e.icon,
				data: e.data,
				layer: 0,
				order: 0,
				original: e
			}));
			return;
		}
		let e = /* @__PURE__ */ new Map(), t = /* @__PURE__ */ new Map();
		for (let n of this.nodes) e.set(n.id, []), t.set(n.id, 0);
		for (let n of this.edges) {
			let r = e.get(n.source);
			r !== void 0 && r.push(n.target);
			let i = t.get(n.target);
			i !== void 0 && t.set(n.target, i + 1);
		}
		let n = /* @__PURE__ */ new Map(), c = [];
		for (let [e, r] of t) r === 0 && (c.push(e), n.set(e, 0));
		if (c.length === 0 && this.nodes.length > 0) {
			let e = this.nodes[0];
			e !== void 0 && (c.push(e.id), n.set(e.id, 0));
		}
		for (; c.length > 0;) {
			let r = c.shift();
			if (r === void 0) continue;
			let i = n.get(r) ?? 0, a = e.get(r);
			if (a !== void 0) for (let e of a) {
				let r = n.get(e), a = i + 1;
				(r === void 0 || a > r) && n.set(e, a);
				let o = t.get(e);
				o !== void 0 && (t.set(e, o - 1), o - 1 <= 0 && c.push(e));
			}
		}
		for (let e of this.nodes) n.has(e.id) || n.set(e.id, 0);
		let l = /* @__PURE__ */ new Map();
		for (let e of this.nodes) {
			let t = n.get(e.id) ?? 0, r = l.get(t);
			r === void 0 ? l.set(t, [e]) : r.push(e);
		}
		let u = this.direction === "TB", d = u ? a : o;
		this.layoutNodes = [];
		for (let [e, t] of l) for (let n = 0; n < t.length; n++) {
			let a = t[n];
			if (a === void 0) continue;
			let o = a.width ?? r, c = a.height ?? i, l, f;
			u ? (l = n * (o + s), f = e * (c + d)) : (l = e * (o + d), f = n * (c + s)), this.layoutNodes.push({
				id: a.id,
				label: a.label,
				type: a.type ?? "process",
				x: l,
				y: f,
				width: o,
				height: c,
				color: a.color,
				icon: a.icon,
				data: a.data,
				layer: e,
				order: n,
				original: a
			});
		}
		u ? this.centerLayersTB() : this.centerLayersLR();
	}
	centerLayersTB() {
		let e = /* @__PURE__ */ new Map();
		for (let t of this.layoutNodes) {
			let n = e.get(t.layer), r = t.x + t.width;
			n === void 0 ? e.set(t.layer, {
				min: t.x,
				max: r
			}) : (t.x < n.min && (n.min = t.x), r > n.max && (n.max = r));
		}
		let t = 0;
		for (let n of e.values()) {
			let e = n.max - n.min;
			e > t && (t = e);
		}
		for (let n of this.layoutNodes) {
			let r = e.get(n.layer);
			if (r !== void 0) {
				let e = r.max - r.min, i = (t - e) / 2;
				n.x += i - r.min;
			}
		}
	}
	centerLayersLR() {
		let e = /* @__PURE__ */ new Map();
		for (let t of this.layoutNodes) {
			let n = e.get(t.layer), r = t.y + t.height;
			n === void 0 ? e.set(t.layer, {
				min: t.y,
				max: r
			}) : (t.y < n.min && (n.min = t.y), r > n.max && (n.max = r));
		}
		let t = 0;
		for (let n of e.values()) {
			let e = n.max - n.min;
			e > t && (t = e);
		}
		for (let n of this.layoutNodes) {
			let r = e.get(n.layer);
			if (r !== void 0) {
				let e = r.max - r.min, i = (t - e) / 2;
				n.y += i - r.min;
			}
		}
	}
	render() {
		for (; this.mainGroup.firstChild !== null;) this.mainGroup.removeChild(this.mainGroup.firstChild);
		this.computeLayout();
		let e = /* @__PURE__ */ new Map();
		for (let t of this.layoutNodes) e.set(t.id, t);
		for (let t of this.edges) {
			let n = e.get(t.source), r = e.get(t.target);
			n === void 0 || r === void 0 || this.renderEdge(t, n, r);
		}
		for (let e of this.layoutNodes) this.renderNode(e);
		this.applyViewBox();
	}
	renderNode(e) {
		let t = document.createElementNS(n, "g");
		t.classList.add("cmm-flow-diagram__node"), e.id === this.selectedNodeId && t.classList.add("cmm-flow-diagram__node--selected"), t.setAttribute("data-node-id", e.id);
		let r = this.createNodeShape(e);
		t.appendChild(r);
		let i = document.createElementNS(n, "text");
		i.classList.add("cmm-flow-diagram__label"), i.setAttribute("x", String(e.x + e.width / 2)), i.setAttribute("y", String(e.y + e.height / 2)), i.textContent = e.label, t.appendChild(i), t.addEventListener("click", (t) => {
			t.stopPropagation(), this.selectedNodeId = e.id, this.render(), this.onNodeClick?.(e.original);
		}), this.mainGroup.appendChild(t);
	}
	createNodeShape(e) {
		let { x: t, y: r, width: i, height: a } = e, o;
		switch (e.type) {
			case "start":
			case "end": {
				let e = document.createElementNS(n, "ellipse");
				e.setAttribute("cx", String(t + i / 2)), e.setAttribute("cy", String(r + a / 2)), e.setAttribute("rx", String(i / 2)), e.setAttribute("ry", String(a / 2)), o = e;
				break;
			}
			case "decision": {
				let e = t + i / 2, s = r + a / 2, c = document.createElementNS(n, "polygon");
				c.setAttribute("points", `${String(e)},${String(r)} ${String(t + i)},${String(s)} ${String(e)},${String(r + a)} ${String(t)},${String(s)}`), o = c;
				break;
			}
			case "io": {
				let e = i * .15, s = document.createElementNS(n, "polygon");
				s.setAttribute("points", `${String(t + e)},${String(r)} ${String(t + i)},${String(r)} ${String(t + i - e)},${String(r + a)} ${String(t)},${String(r + a)}`), o = s;
				break;
			}
			default: {
				let e = document.createElementNS(n, "rect");
				e.setAttribute("x", String(t)), e.setAttribute("y", String(r)), e.setAttribute("width", String(i)), e.setAttribute("height", String(a)), e.setAttribute("rx", "8"), e.setAttribute("ry", "8"), o = e;
				break;
			}
		}
		return o.classList.add("cmm-flow-diagram__node-shape"), e.color !== void 0 && o.setAttribute("fill", e.color), o;
	}
	renderEdge(e, t, r) {
		let i = document.createElementNS(n, "g");
		i.classList.add("cmm-flow-diagram__edge");
		let a = e.type ?? "solid";
		a === "dashed" ? i.classList.add("cmm-flow-diagram__edge--dashed") : a === "dotted" && i.classList.add("cmm-flow-diagram__edge--dotted"), e.animated === !0 && i.classList.add("cmm-flow-diagram__edge--animated"), i.setAttribute("data-edge-id", e.id);
		let o = this.getNodePort(t, "out"), s = this.getNodePort(r, "in"), c = document.createElementNS(n, "path");
		c.classList.add("cmm-flow-diagram__edge-path");
		let l = this.direction === "TB", u;
		if (l) {
			let e = Math.abs(s.y - o.y) / 2;
			u = `M ${String(o.x)} ${String(o.y)} C ${String(o.x)} ${String(o.y + e)}, ${String(s.x)} ${String(s.y - e)}, ${String(s.x)} ${String(s.y)}`;
		} else {
			let e = Math.abs(s.x - o.x) / 2;
			u = `M ${String(o.x)} ${String(o.y)} C ${String(o.x + e)} ${String(o.y)}, ${String(s.x - e)} ${String(s.y)}, ${String(s.x)} ${String(s.y)}`;
		}
		if (c.setAttribute("d", u), c.setAttribute("marker-end", `url(#${this.diagramId}-arrow)`), e.color !== void 0 && c.setAttribute("stroke", e.color), i.appendChild(c), e.label !== void 0) {
			let t = (o.x + s.x) / 2, r = (o.y + s.y) / 2, a = document.createElementNS(n, "text");
			a.classList.add("cmm-flow-diagram__edge-label"), a.setAttribute("x", String(t)), a.setAttribute("y", String(r - 6)), a.textContent = e.label, i.appendChild(a);
		}
		i.addEventListener("click", (t) => {
			t.stopPropagation(), this.onEdgeClick?.(e);
		}), this.mainGroup.appendChild(i);
	}
	getNodePort(e, t) {
		let n = e.x + e.width / 2, r = e.y + e.height / 2;
		return this.direction === "TB" ? t === "out" ? {
			x: n,
			y: e.y + e.height
		} : {
			x: n,
			y: e.y
		} : t === "out" ? {
			x: e.x + e.width,
			y: r
		} : {
			x: e.x,
			y: r
		};
	}
	createArrowMarker() {
		let e = document.createElementNS(n, "marker");
		e.setAttribute("id", `${this.diagramId}-arrow`), e.setAttribute("markerWidth", String(c)), e.setAttribute("markerHeight", String(c)), e.setAttribute("refX", String(c)), e.setAttribute("refY", String(c / 2)), e.setAttribute("orient", "auto-start-reverse"), e.setAttribute("markerUnits", "userSpaceOnUse");
		let t = document.createElementNS(n, "polygon");
		t.classList.add("cmm-flow-diagram__arrowhead"), t.setAttribute("points", `0 0, ${String(c)} ${String(c / 2)}, 0 ${String(c)}`), e.appendChild(t), this.defsEl.appendChild(e);
	}
	applyViewBox() {
		this.svg.setAttribute("viewBox", `${String(this.viewBox.x)} ${String(this.viewBox.y)} ${String(this.viewBox.w)} ${String(this.viewBox.h)}`);
	}
	handleWheel(e) {
		e.preventDefault();
		let t = e.deltaY > 0 ? 1.1 : .9, n = this.el.getBoundingClientRect(), r = (e.clientX - n.left) / n.width * this.viewBox.w + this.viewBox.x, i = (e.clientY - n.top) / n.height * this.viewBox.h + this.viewBox.y, a = this.viewBox.w * t, o = this.viewBox.h * t;
		this.viewBox.x = r - (r - this.viewBox.x) * (a / this.viewBox.w), this.viewBox.y = i - (i - this.viewBox.y) * (o / this.viewBox.h), this.viewBox.w = a, this.viewBox.h = o, this.applyViewBox();
	}
	handleMouseDown(e) {
		if (e.button !== 0) return;
		let t = e.target;
		t !== null && t.closest(".cmm-flow-diagram__node, .cmm-flow-diagram__edge") !== null || (this.isPanning = !0, this.panStart = {
			x: e.clientX,
			y: e.clientY
		}, this.panOrigin = {
			x: this.viewBox.x,
			y: this.viewBox.y
		});
	}
	handleMouseMove(e) {
		if (!this.isPanning) return;
		let t = this.el.getBoundingClientRect(), n = this.viewBox.w / t.width, r = this.viewBox.h / t.height;
		this.viewBox.x = this.panOrigin.x - (e.clientX - this.panStart.x) * n, this.viewBox.y = this.panOrigin.y - (e.clientY - this.panStart.y) * r, this.applyViewBox();
	}
	handleMouseUp() {
		this.isPanning = !1;
	}
	buildClassName(e) {
		let t = ["cmm-flow-diagram"];
		return e !== void 0 && t.push(e), t.join(" ");
	}
};
//#endregion
export { l as FlowDiagram };

//# sourceMappingURL=index.js.map