(function (global) {

	var dispatch = d3.dispatch("click");

// ----

/*This software is released under the MIT License

MIT License 2014 Denes Csala http://www.csaladen.es

The following software uses the javascript frameworks below,
all of which are distributed under the MIT or GNU/GPL license:
D3.js http://d3js.org/  data-oriented javascript framework.
	- Sankey plugin http://bost.ocks.org/mike/sankey/ for D3.js (modified) by Mike Bostock,
	  which is based on the initial version http://tamc.github.io/Sankey/ by Thomas Counsell.
	  I have incorporated the ability to render Sankey cycles, as pioneered by https://github.com/cfergus
	- Dragdealer.js href="http://skidding.github.io/dragdealer/ by Ovidiu Chereches
*/

//<!--DATA INIT-->

var data={"nodes": [], "links": []}

//<!--DATA ENTRY-->

nodesform=d3.select("#nodes-form");
function addnode() {
	var a=nodesform.append("div");
	a.text(nodesform[0][0].children.length-1+' ');
	a.append("input").attr("value",'{"name":"New Node"}');
}
function removenode() {
	nodesform[0][0].children[nodesform[0][0].children.length-1].remove("div")
}
linksform=d3.select("#links-form");
function addlink() {
	linksform.append("div").append("input").attr("value",'{"source":0,"target":1,"value":0.52}');
}
function removelink() {
	linksform[0][0].children[linksform[0][0].children.length-1].remove("div")
}
function draw() {
	change(data);
}
function save(){
	d3.select('#save').style('z-index',100).transition().style('opacity',0.9);
	st='{"sankey":{"nodes":['
	for (i = 0; i < nodesform[0][0].children.length; i++) {
		st=st+nodesform[0][0].children[i].children[0].value+',';
	}
	st=st.substring(0, st.length - 1)+'],"links":[';
	for (i = 0; i < linksform[0][0].children.length; i++) {
		st=st+linksform[0][0].children[i].children[0].value+',';
	}
	st = st.substring(0, st.length - 1)+']},"params":['+densityslider.value.current[0]+','+opacityslider.value.current[0]+','+labelformat+','+labeltextformat+','+showlinkcount+']';
	if (document.getElementById("fixedlayout").checked){
		var coords=[]
		sankey.nodes().forEach(function(d){
			coords.push([d.x,d.y])
		})
		st=st+',"fixedlayout":'+JSON.stringify(coords);
	}
	st=st+'}';
	d3.select('#savetext').text(st);
}
function load(){
	d3.select('#load').style('z-index',100).transition().style('opacity',0.9);
}
function loadsubmit(){
	d3.select('#load').transition().style('opacity',0).style('z-index',-1);
	var rawtext=d3.select('#load')[0][0].children[1].value;
	if (rawtext!="") {
		//parse data
		var rawdata=JSON.parse(rawtext);
		if ("sankey" in rawdata) {
			var newdata=rawdata.sankey;
		}
		else {
			var newdata=rawdata;
		}
		var loadtext=JSON.stringify(newdata)
		//remove existing node entry boxes
		var n=nodesform[0][0].children.length;
		for (i = 0; i < n; i++) {
			nodesform[0][0].children[0].remove("div");
		}
		//remove existing link entry boxes
		var n=linksform[0][0].children.length;
		for (i = 0; i < n; i++) {
			linksform[0][0].children[0].remove("div");
		}
		//add new node entry boxes
		var newdata2=JSON.parse(loadtext.substring(loadtext.indexOf('"nodes":[')+8, loadtext.indexOf('"links":[')-1));
		for (i = 0; i < newdata2.length; i++) {
			var a=nodesform.append("div");
			a.text(nodesform[0][0].children.length-1+' ');
			a.append("input").attr("value",JSON.stringify(newdata2[i]));
		}
		//add new link entry boxes
		var newdata2=JSON.parse(loadtext.substring(loadtext.indexOf('"links":[')+8, loadtext.length - 1))
		for (i = 0; i < newdata2.length; i++) {
			linksform.append("div").append("input").attr("value",JSON.stringify(newdata2[i]));
		}
		//set parameters
		if ("fixedlayout" in rawdata) {
			fixedlayout=document.getElementById("ignorelayout").checked?[]:rawdata.fixedlayout;
		} else {
			fixedlayout=[];
		}
		if ("params" in rawdata) {
			labelformat=rawdata.params[2];
			labeltextformat=rawdata.params[3];
			if (rawdata.params.length>4) showlinkcount=rawdata.params[4];
			else showlinkcount=0;
			document.getElementById("vlabel").checked=(labelformat==0)?true:false;
			document.getElementById("tlabel").checked=(labeltextformat==0)?true:false;
			document.getElementById("clabel").checked=(showlinkcount==1)?true:false;
			densityslider.setValue(rawdata.params[0]);
			opacityslider.setValue(rawdata.params[1]);
		}
		else {
			change(newdata);
		}
	}
}

//<!--SANKEY DIAGRAM-->

var parallelrendering=false;
var minnodewidth = 50;
var padding = 28;
var labelformat = 0;
var labeltextformat = 0;
var showlinkcount = 0;
var paddingmultiplier = 100;
var lowopacity = 0.3;
var highopacity = 0.7;
var fixedlayout=[];
var sankeyColor = d3.scale.category20();
var sankeyNumberFormat = d3.format(",.0f");

// d3.select("#ndec")
// .on("change",draw);
// d3.select("#ldec")
// .on("change",draw);

var margin = {
        top: 10,
        right: 10,
        bottom: 10,
        left: 40
    };
var width = 1000; //document.getElementById("chart").offsetWidth - margin.left - margin.right,
var height = 500; // document.getElementById("chart").offsetHeight - margin.bottom;
var svg = null;//d3.select("#chart").append("svg")
//svg.append("rect").attr("x",0).attr("y",0).attr("width","100%").attr("height","100%").attr("fill","white").attr('class','background')
//svg=svg.attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom).append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

//set svg background color via rectangle trick
// d3.select("#chart").select("svg")

var sankey = null;
// var sankey = d3.sankey().nodeWidth(30).nodePadding(padding).size([width, height]);
// var path = sankey.reversibleLink();
var change = function(d) {

	svg.selectAll("g").remove();
	sankey = d3.sankey().nodeWidth(30).nodePadding(padding).size([width, height]);
	sankey.nodes(d.nodes).links(d.links).layout(500);
	var g = svg.append("g") //link
		.selectAll(".link").data(d.links).enter().append("g").attr("class", "link").sort(function(j, i) {
			return i.dy - j.dy
		});
	var path = sankey.reversibleLink();
	var h = g.append("path") //path0
		.attr("d", path(0));
	var f = g.append("path") //path1
		.attr("d", path(1));
	var e = g.append("path") //path2
		.attr("d", path(2));
	g.attr("fill", function(i) {
			if (i.fill) return i.fill;
			else if (i.source.fill) return i.source.fill;
			else return i.source.color = sankeyColor(i.source.name.replace(/ .*/, ""))
		}).attr("opacity", lowopacity).on("mouseover", function(d) {
			d3.select(this).style('opacity', highopacity);
		}).on("mouseout", function(d) {
			d3.select(this).style('opacity', lowopacity);
		}).append("title")
		.text(sankeyEdgeTitle);
	var c = svg.append("g") //node
		.selectAll(".node").data(d.nodes).enter().append("g").attr("class", "node").attr("transform", function(i) {
			return "translate(" + i.x + "," + i.y + ")"
		}).call(d3.behavior.drag().origin(function(i) {
			return i
		}).on("dragstart", function() {
			this.parentNode.appendChild(this)
		}).on("drag", samkeyOnDragMove));
	c.append("rect") //node
		.attr("height", function(i) {
			return i.dy
		}).attr("width", sankey.nodeWidth()).style("fill", function(i) {
			if (i.fill) return i.color = i.fill;
								else return i.color = sankeyColor(i.name.replace(/ .*/, ""))
		}).style("stroke", function(i) {
			return d3.rgb(i.color).darker(2)
		}).on("mouseover", function(d) {
			svg.selectAll(".link").filter(function(l) {
				return l.source == d || l.target == d;
			}).transition().style('opacity', highopacity);
		}).on("mouseout", function(d) {
			svg.selectAll(".link").filter(function(l) {
				return l.source == d || l.target == d;
			}).transition().style('opacity', lowopacity);
		}).on("dblclick", function(d) {
			svg.selectAll(".link").filter(function(l) {
				return l.target == d;
			}).attr("display", function() {
				if (d3.select(this).attr("display") == "none") return "inline"
				else return "none"
			});
		}).append("title").text(sankeyNodeTitle);
	c.append("text") //node
		.attr("x", -6).attr("y", function(i) {
			return i.dy / 2
		}).attr("dy", ".35em").attr("text-anchor", "end").attr("font-size","16px")
		.text(sankeyNodeLabel)
		.filter(function(i) {
			return i.x < width / 2
		}).attr("x", 6 + sankey.nodeWidth()).attr("text-anchor", "start")
	if (showlinkcount>0) c.append("text") //node
		.attr("x", -6).attr("y", function(i) {
			return i.dy / 2 + 20
		}).attr("dy", ".35em").attr("text-anchor", "end").attr("font-size","16px")
		.text(function(i) {
			return "→ "+(i.targetLinks.length)+" | "+(i.sourceLinks.length)+" →";
		}).filter(function(i) {
			return i.x < width / 2
		}).attr("x", 6 + sankey.nodeWidth()).attr("text-anchor", "start")
	c.append("text") //node
		.attr("x", function(i) {return -i.dy / 2})
		.attr("y", function(i) {return i.dx / 2 + 9})
		.attr("transform", "rotate(270)").attr("text-anchor", "middle").attr("font-size","23px").text(function(i) {
			if ((i.dy>minnodewidth)&&(labelformat<1)){
				return sankeyNumberFormat(i.value);
			}
		}).attr("fill",function(d){
			return d3.rgb(d["color"]).brighter(2)
		}).attr("stroke",function(d){
			return d3.rgb(d["color"]).darker(2)
		}).attr("stroke-width","1px");

		svg.selectAll('rect')
		.on('mouseover', (a, b, c, d, e) => {console.log('mouseover', a, b, c, d, e)})
		.on('mouseout', (a, b, c, d, e) => {console.log('mouseout', a, b, c, d, e)})
		.on('mousedown', (a, b, c, d, e) => {console.log('mousedown', a, b, c, d, e)})
		.on('mouseup', (a) => {
			dispatch.click({
				nativeEvent: d3.event,
				node: a,
				element: d3.event.srcElement
			})
		});

		function samkeyOnDragMove(i) {
			// if (document.getElementById("ymove").checked) {
			// 	if (document.getElementById("xmove").checked) {
			// 		d3.select(this).attr("transform", "translate(" + (i.x = Math.max(0, Math.min(width - i.dx, d3.event.x))) + "," + (i.y = Math.max(0, Math.min(height - i.dy, d3.event.y))) + ")")
			// 	} else {
			dragged = true
			d3.select(this).attr("transform", "translate(" + i.x + "," + (i.y = Math.max(0, Math.min(height - i.dy, d3.event.y))) + ")")
			// 	}
			// } else {
			// 	if (document.getElementById("xmove").checked) {
			// 		d3.select(this).attr("transform", "translate(" + (i.x = Math.max(0, Math.min(width - i.dx, d3.event.x))) + "," + i.y + ")")
			// 	}
			// }
			sankey.relayout();
			f.attr("d", path(1)); // TODO: global var f
			h.attr("d", path(0)); // TODO: global var h
			e.attr("d", path(2)); // TODO: global var e
		}

};
// draw();

function sankeyEdgeTitle(i) {
	return i.source.name + " → " + i.target.name + "\n" + sankeyNumberFormat(i.value)
}
function sankeyNodeTitle(i) {
	if (i.label) return i.label + "\n" + sankeyNumberFormat(i.value)
	return i.name + "\n" + sankeyNumberFormat(i.value)
}

function sankeyNodeLabel(i) {
	if (labeltextformat < 1) {
		if (i.label) return (i.label.length > 20) ? i.label.substr(0, 20) + '...' : i.label
		return i.name;
	} else {
		return "";
	}
}

	var renderGraph = (htmlNode, data, opts) => {
		var opts = opts || {}
		if (!htmlNode) throw "Missing html node";
		if (!data) throw "Missing data";
		// console.log('renderGraph data', data)

		htmlNode.append("rect").attr("x",0).attr("y",0).attr("width","100%").attr("height","100%").attr("fill","white")
		margin = {
			top: 10,
			right: 20,
			bottom: 10,
			left: 40
		};
		width = (opts.width) ? opts.width - margin.left - margin.right : 1020;
		height = (opts.height) ? opts.height : 500;
		htmlNode.attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom)
		svg = htmlNode.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

		change(data);

		return dispatch
	}

	global.parallelrendering = parallelrendering
	global.fixedlayout = fixedlayout
	global.renderGraph = renderGraph
})(window)