//- UNCLASSIFIED
extends base
append base_help
	:markdown
		Display d3 edge bundle chart using parameters:

			src = source returning IMPORTS = [ { name: "x.y.z ...", size: N, doc: "", imports: IMPORTS}, ...]
			w = drawing width
			h = drawing height
			debug = level of debugging alerts
			node,children,value,doc = src keys

append base_parms
	- tech = "d3v5"
	
append base_head

	style.
		node circle {
		fill: #fff;
			stroke: steelblue;
			stroke-width: 3px;
		}

		.node text {
			font: 12px sans-serif;
		}

		.link {
			fill: none;
			stroke: #ccc;
			stroke-width: 2px;
		}

	script.
		var opts = {
			ds: "!{query.src}" || "/stores/flare.json",
			/*
			"#{query.pivots}"
				? "!{query.src}.tree?name=#{query.name}&_sort=#{query.pivots}"
				: "#{query.name}"
							? "!{query.src}.schema?name=#{query.name}"
							: "!{query.src}" || "/stores/flare.json",
			*/
			
			url: "#{url}",
			family: "cluster",

			dims: {
				margin: {top: 20, right: 90, bottom: 30, left: 90},
				width: parseInt("#{query.w}") || 1200,
				height: parseInt("#{query.h}") || 500
			},
			debug: parseInt("#{query.debug}"),

			keys: {
				NODE: "#{query.node}" || "name",
				CHILDREN: "#{query.children}" || "children",
				VALUE: "#{query.value}" || "value",
				DOC: "#{query.doc}" || "doc"
			}
		};

		const {NODE, CHILDREN, VALUE, DOC} = opts.keys;
										
append base_body
	script.
		Fetch( opts, (data,svg) => {
			function overed(d) {
				link.style("mix-blend-mode", null);
				d3.select(this).attr("font-weight", "bold");
				d3.selectAll(d.incoming.map(d => d.path)).attr("stroke", colorin).raise();
				d3.selectAll(d.incoming.map(([d]) => d.text)).attr("fill", colorin).attr("font-weight", "bold");
				d3.selectAll(d.outgoing.map(d => d.path)).attr("stroke", colorout).raise();
				d3.selectAll(d.outgoing.map(([, d]) => d.text)).attr("fill", colorout).attr("font-weight", "bold");
			}

			function outed(d) {
				link.style("mix-blend-mode", "multiply");
				d3.select(this).attr("font-weight", null);
				d3.selectAll(d.incoming.map(d => d.path)).attr("stroke", null);
				d3.selectAll(d.incoming.map(([d]) => d.text)).attr("fill", null).attr("font-weight", null);
				d3.selectAll(d.outgoing.map(d => d.path)).attr("stroke", null);
				d3.selectAll(d.outgoing.map(([, d]) => d.text)).attr("fill", null).attr("font-weight", null);
			}
			
			function bilink(root) {
				alert("bi");
				const map = new Map(root.leaves().map(d => [id(d), d]));
				alert("map");
				for (const d of root.leaves()) d.incoming = [], d.outgoing = d.data.imports.map(i => [d, map.get(i)]);
				for (const d of root.leaves()) for (const o of d.outgoing) o[1].incoming.push(o);
				return root;
			}

			function id(node) {
				return `${node.parent ? id(node.parent) + "." : ""}${node.data.name}`;
			}

			function hierarchy(data, delimiter = ".") {
				let root;
				const map = new Map;
				data.forEach(function find(data) {
					const {name} = data;
					console.log(name);
					if (map.has(name)) return map.get(name);
					const i = name.lastIndexOf(delimiter);
					map.set(name, data);
					if (i >= 0) {
						find({name: name.substring(0, i), children: []}).children.push(data);
						data.name = name.substring(i + 1);
					} else {
						root = data;
					}
					return data;
				});
				return root;
			}

			var
				width = svg.attr("width"),
				height = svg.attr("height");

			svg //= d3.create("svg")
					.attr("viewBox", [-width / 2, -width / 2, width, width]);

			alert(width);

			var
				colorin = "#00f",
				colorout = "#f00",
				colornone = "#ccc",
				radius = width / 2,
				line = d3.lineRadial()
					.curve(d3.curveBundle.beta(0.85))
					.radius(d => d.y)
					.angle(d => d.x),
				tree = d3.cluster()
					.size([2 * Math.PI, radius - 100]);

			alert("a0");
			const
				a0 = hierarchy( [
					{name: "a.b", size:10, imports: ["b.x","b.y"]},
					{name: "b.x", size:1, imports:[]},
					{name: "b.y", size:2, imports:[]}
				 ] );
					
			alert(JSON.stringify(a0));
			alert("a1");
			const a1 = d3.hierarchy(a0);
					
			alert("a2");
			alert(d3.ascending);
					
			const a2 = a1
					.sort((a, b) => d3.ascending(a.height, b.height) || d3.ascending(a.data.name, b.data.name));
					
			alert("a3");
			const a3 = bilink(a2);
												
			alert("tree");
			const root = tree(a3);

			alert("node");
			const node = svg.append("g")
					.attr("font-family", "sans-serif")
					.attr("font-size", 10)
				.selectAll("g")
				.data(root.leaves())
				.join("g")
					.attr("transform", d => `rotate(${d.x * 180 / Math.PI - 90}) translate(${d.y},0)`)
				.append("text")
					.attr("dy", "0.31em")
					.attr("x", d => d.x < Math.PI ? 6 : -6)
					.attr("text-anchor", d => d.x < Math.PI ? "start" : "end")
					.attr("transform", d => d.x >= Math.PI ? "rotate(180)" : null)
					.text(d => d.data.name)
					.each(function(d) { d.text = this; })
					.on("mouseover", overed)
					.on("mouseout", outed)
					.call(text => text.append("title").text(d => 
						`${id(d)}${d.outgoing.length} outgoing${d.incoming.length} incoming`
					));

			alert("link");
			const link = svg.append("g")
					.attr("stroke", colornone)
					.attr("fill", "none")
				.selectAll("path")
				.data(root.leaves().flatMap(leaf => leaf.outgoing))
				.join("path")
					.style("mix-blend-mode", "multiply")
					.attr("d", ([i, o]) => line(i.path(o)))
					.each(function(d) { d.path = this; });

			
		});

//- UNCLASSIFIED
