//- UNCLASSIFIED
extends base
append base_help
	:markdown
		Display d3 fan chart using parameters:

			src = source returning NODES = [ { name: "...", value: N, doc: "...", children: NODES }, ... ]
			w = drawing width
			h = drawing height
			debug = level of debugging alerts
			node,children,value,doc = src keys

		//- legacy
			name = "name" || "name%..." || "" of source record(s)
			pivots = "key,key,..." || "" source record grouping 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}" || "0"),

			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) => {	
			//console.log(data);
																			 
			function collapse(d) {	// Collapse the node and all it's children
			  if(d.children) {
				d._children = d.children
				d._children.forEach(collapse)
				d.children = null
			  }
			}

			function update(source) {

			  // Assigns the x and y position for the nodes
			  var treeData = treefan(root);

			  // Compute the new tree layout.
			  var nodes = treeData.descendants(),
				  links = treeData.descendants().slice(1);

			  // Normalize for fixed-depth.
			  nodes.forEach( d => d.y = d.depth * 180 );

			  // ****************** Nodes section ***************************

			  // Update the nodes...
			  var 
					id = 0,
					node = svg.selectAll('g.node')
						.data(nodes, d => d.id || (d.id = ++id) );

			  // Enter any new modes at the parent's previous position.
			  var nodeEnter = node.enter().append('g')
				.attr('class', 'node')
				.attr("transform", d => "translate(" + source.y0 + "," + source.x0 + ")" )
				.on('click', d => {		// Toggle children on click.
					function details(doc) { // dump nods details
						if ( isString(doc) ) 
							msg.html( doc );

						else
							msg.text( JSON.stringify( doc ) );
					}

					if ( d.children ) {
						d._children = d.children;
						d.children = null;
					}
					else {
						d.children = d._children;
						d._children = null;
					}
					update(d);
					if ( doc = d.data[DOC]) details( doc ); 
				});

			  // Add Circle for the nodes
			  nodeEnter.append('circle')
				  .attr('class', 'node')
				  .attr('r', 5)
				  .style("fill", d => d._children ? "lightsteelblue" : "#fff" );

			  // Add labels for the nodes
			  nodeEnter.append('text')
				  .attr("dy", ".35em")
				  .attr("x", d => d.children || d._children ? -13 : 13 )
				  .attr("text-anchor", d  => d.children || d._children ? "end" : "start" )
				  .text( d => d.data[NODE] );

			  // UPDATE
			  var nodeUpdate = nodeEnter.merge(node);

			  // Transition to the proper position for the node
			  nodeUpdate.transition()
				.duration(duration)
				.attr("transform", function(d) { 
					return "translate(" + d.y + "," + d.x + ")";
				 });

			  // Update the node attributes and style
			  nodeUpdate.select('circle.node')
				.attr('r', 5)
				.style("fill", d => d._children ? "lightsteelblue" : "red" )
				.attr('cursor', 'pointer');

			  // Remove any exiting nodes
			  var nodeExit = node.exit().transition()
				  .duration(duration)
				  .attr("transform", d => "translate(" + source.y + "," + source.x + ")" )
				  .remove();

			  // On exit reduce the node circles size to 0
			  nodeExit.select('circle')
				.attr('r', 1);

			  // On exit reduce the opacity of text labels
			  nodeExit.select('text')
				.style('fill-opacity', 1e-6);

			  // ****************** links section ***************************

			  // Update the links...
			  var link = svg.selectAll('path.link')
				  .data(links, d => d.id );

			  // Enter any new links at the parent's previous position.
			  var linkEnter = link.enter().insert('path', "g")
				  .attr("class", "link")
				  .attr('d', d => {
					var o = {x: source.x0, y: source.y0};
					return diagonal(o, o);
				  });

			  // UPDATE
			  var linkUpdate = linkEnter.merge(link);

			  // Transition back to the parent element position
			  linkUpdate.transition()
				  .duration(duration)
				  .attr('d', d => diagonal(d, d.parent) );

			  // Remove any exiting links
			  var linkExit = link.exit().transition()
				  .duration(duration)
				  .attr('d', d => {
					var o = {x: source.x, y: source.y};
					return diagonal(o, o);
				  })
				  .remove();

			  nodes.forEach( d => {		// Store the old positions for transition.
				d.x0 = d.x;
				d.y0 = d.y;
			  });

			  function diagonal(s, d) {	// Creates a curved (diagonal) path from parent to the child nodes
				return `M ${s.y} ${s.x}
						C ${(s.y + d.y) / 2} ${s.x},
						  ${(s.y + d.y) / 2} ${d.x},
						  ${d.y} ${d.x}`;
			  }

			}

			/*
			var svg = body.append("svg")
				.attr("width", width + margin.right + margin.left)
				.attr("height", height + margin.top + margin.bottom)
				.append("g")
				.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
			*/
			var 
				duration = 750,
				width = svg.attr("width"),
				height = svg.attr("height"),
				msg = d3.select("body").append("p").text("details: "),
				
				svg = svg.append("g")
						.attr("transform", "translate(" + opts.dims.margin.left + "," + opts.dims.margin.top + ")");
			
				// declares a tree layout and assigns the size
				treefan = d3.tree().size([height, width]),

				// Assigns parent, children, height, depth
				root = d3.hierarchy( data[0] || data , d => d[CHILDREN] );
			
			root.x0 = height / 2;
			root.y0 = 0;

			// Collapse after the second level
			root.children.forEach(collapse);

			update(root);
		});

//- UNCLASSIFIED
