// http://jsfiddle.net/stephenboak/hYuPb/

// Wrapper function
function do_pie(name, update_url, url_params, units, refresh) {
	var pie = new PieChart(name, update_url, url_params, units, refresh);
	if (refresh)
		pie.setInterval(setInterval(function () { pie.update(); }, refresh));

	// Return new class instance, with
	return pie;
}

function PieChart(name, update_url, url_params, units, refresh) {

	// Add object properties like this
	this.name = name;
	this.update_url = update_url;
	this.url_params = url_params;
	this.units = units;
	this.refresh = refresh;
	this.pieInterval;

	var pieData = [];
	var oldPieData = [];
	var filteredPieData = [];
	var rsp = create_pie_chart(name, units);
	var arc_group = rsp[0];
	var donut = rsp[1];
	var totalValue = rsp[2];
	var totalUnits = rsp[3];
	var color = rsp[4];
	var tweenDuration = rsp[5];
	var arc = rsp[6];
	var label_group = rsp[7];
	var center_group = rsp[8];
	var r = rsp[9];
	var textOffset = rsp[10];


	// to run each time data is generated

	this.update = function () {
		// console.log(this.name);
		// console.log(this.url_params);
		$.ajax({
			type: 'GET',
			url: this.update_url,
			data: this.url_params,
			success: function (content) {
				let parsed_content;

				if (typeof (content) == "object")
					parsed_content = content;
				else if (typeof (content) == "string")
					parsed_content = jQuery.parseJSON(content);

				if (parsed_content)
					update_pie_chart(parsed_content);
			}
		});
	}

	///////////////////////////////////////////////////////////
	// STREAKER CONNECTION ////////////////////////////////////
	///////////////////////////////////////////////////////////

	// Needed to draw the pie immediately
	this.update();
	this.update();

	// var updateInterval = window.setInterval(update, refresh);

	function compare_by_label(a, b) {
		if (a.label < b.label) {
			return -1;
		} else if (a.label > b.label) {
			return 1;
		} else {
			return 0;
		}
	}

	function update_pie_chart(data) {
		if (data.rsp) // detect REST API v1
			data = data.rsp;

		data.sort(compare_by_label);
		streakerDataAdded = data;
		oldPieData = filteredPieData;
		pieData = donut(streakerDataAdded);

		var totalOctets = 0;
		filteredPieData = pieData.filter(filterData);
		function filterData(element, index, array) {
			element.name = streakerDataAdded[index].label;
			element.value = streakerDataAdded[index].value;
			element.url = streakerDataAdded[index].url;
			totalOctets += element.value;
			return (element.value > 0);
		}

		if ((filteredPieData.length > 0) && (oldPieData.length > 0)) {
			//REMOVE PLACEHOLDER CIRCLE
			arc_group.selectAll("circle").remove();

			if (totalValue) {
				totalValue.text(function () {
					var kb = totalOctets / 1024;
					return kb.toFixed(1);
					//return bchart.label.abbreviated(totalOctets*8);
				});
			}

			//DRAW ARC PATHS
			paths = arc_group.selectAll("path").data(filteredPieData);
			paths.enter().append("svg:path")
				.attr("stroke", "white")
				.attr("stroke-width", 0.5)
				.attr("fill", function (d, i) { return color(i); })
				.transition()
				.duration(tweenDuration)
				.attrTween("d", pieTween);
			paths
				.transition()
				.duration(tweenDuration)
				.attrTween("d", pieTween);
			paths.exit()
				.transition()
				.duration(tweenDuration)
				.attrTween("d", removePieTween)
				.remove();

			//DRAW TICK MARK LINES FOR LABELS
			lines = label_group.selectAll("line").data(filteredPieData);
			lines.enter().append("svg:line")
				.attr("x1", 0)
				.attr("x2", 0)
				.attr("y1", -r - 3)
				.attr("y2", -r - 8)
				.attr("stroke", "gray")
				.attr("transform", function (d) {
					return "rotate(" + (d.startAngle + d.endAngle) / 2 * (180 / Math.PI) + ")";
				});
			lines.transition()
				.duration(tweenDuration)
				.attr("transform", function (d) {
					return "rotate(" + (d.startAngle + d.endAngle) / 2 * (180 / Math.PI) + ")";
				});
			lines.exit().remove();

			//DRAW LABELS WITH PERCENTAGE VALUES
			valueLabels = label_group.selectAll("text.value").data(filteredPieData)
				.attr("dy", function (d) {
					if ((d.startAngle + d.endAngle) / 2 > Math.PI / 2 && (d.startAngle + d.endAngle) / 2 < Math.PI * 1.5) {
						return 5;
					} else {
						return -7;
					}
				})
				.attr("text-anchor", function (d) {
					if ((d.startAngle + d.endAngle) / 2 < Math.PI) {
						return "beginning";
					} else {
						return "end";
					}
				})
				.text(function (d) {

					const percentage = (d.value / totalOctets) * 100;
					// approssimate the number to the third deciaml digit and show only the first decimal
					let percentageLabel = percentage.toFixed(1) + "%";
					return percentageLabel;
				});

			valueLabels.enter().append("svg:text")
				.attr("class", "value")
				.attr("transform", function (d) {
					return "translate(" + Math.cos(((d.startAngle + d.endAngle - Math.PI) / 2)) * (r + textOffset) + "," + Math.sin((d.startAngle + d.endAngle - Math.PI) / 2) * (r + textOffset) + ")";
				})
				.attr("dy", function (d) {
					if ((d.startAngle + d.endAngle) / 2 > Math.PI / 2 && (d.startAngle + d.endAngle) / 2 < Math.PI * 1.5) {
						return 5;
					} else {
						return -7;
					}
				})
				.attr("text-anchor", function (d) {
					if ((d.startAngle + d.endAngle) / 2 < Math.PI) {
						return "beginning";
					} else {
						return "end";
					}
				}).text(function (d) {
					if (totalOctets <= 1) return "";
					const percentage = (d.value / totalOctets) * 100;
					let percentageLabel = percentage.toFixed(1) + "%";
					return percentageLabel;
				});

			valueLabels.transition().duration(tweenDuration).attrTween("transform", textTween);
			valueLabels.exit().remove();

			//DRAW LABELS WITH ENTITY NAMES
			nameLabels = label_group.selectAll("text.units").data(filteredPieData)
				.attr("dy", function (d) {
					if ((d.startAngle + d.endAngle) / 2 > Math.PI / 2 && (d.startAngle + d.endAngle) / 2 < Math.PI * 1.5) {
						return 17;
					} else {
						return 5;
					}
				})
				.attr("text-anchor", function (d) {
					if ((d.startAngle + d.endAngle) / 2 < Math.PI) {
						return "beginning";
					} else {
						return "end";
					}
				}).text(function (d) {
					return d.name;
				})
				.on("click", function (d) { if (d.url) window.location.href = d.url; });

			nameLabels.enter().append("svg:text")
				.attr("class", "units")
				.attr("transform", function (d) {
					return "translate(" + Math.cos(((d.startAngle + d.endAngle - Math.PI) / 2)) * (r + textOffset) + "," + Math.sin((d.startAngle + d.endAngle - Math.PI) / 2) * (r + textOffset) + ")";
				})
				.attr("dy", function (d) {
					if ((d.startAngle + d.endAngle) / 2 > Math.PI / 2 && (d.startAngle + d.endAngle) / 2 < Math.PI * 1.5) {
						return 17;
					} else {
						return 5;
					}
				})
				.attr("text-anchor", function (d) {
					if ((d.startAngle + d.endAngle) / 2 < Math.PI) {
						return "beginning";
					} else {
						return "end";
					}
				}).text(function (d) {
					return d.name;
				})
				.on("click", function (d) { if (d.url) window.location.href = d.url; });

			nameLabels.transition().duration(tweenDuration).attrTween("transform", textTween);

			nameLabels.exit().remove();
		}
	}

	///////////////////////////////////////////////////////////
	// FUNCTIONS //////////////////////////////////////////////
	///////////////////////////////////////////////////////////

	// Interpolate the arcs in data space.
	function pieTween(d, i) {
		var s0;
		var e0;
		if (oldPieData[i]) {
			s0 = oldPieData[i].startAngle;
			e0 = oldPieData[i].endAngle;
		} else if (!(oldPieData[i]) && oldPieData[i - 1]) {
			s0 = oldPieData[i - 1].endAngle;
			e0 = oldPieData[i - 1].endAngle;
		} else if (!(oldPieData[i - 1]) && oldPieData.length > 0) {
			s0 = oldPieData[oldPieData.length - 1].endAngle;
			e0 = oldPieData[oldPieData.length - 1].endAngle;
		} else {
			s0 = 0;
			e0 = 0;
		}
		var i = d3.interpolate({ startAngle: s0, endAngle: e0 }, { startAngle: d.startAngle, endAngle: d.endAngle });
		return function (t) {
			var b = i(t);
			return arc(b);
		};
	}

	function removePieTween(d, i) {
		s0 = 2 * Math.PI;
		e0 = 2 * Math.PI;
		var i = d3.interpolate({ startAngle: d.startAngle, endAngle: d.endAngle }, { startAngle: s0, endAngle: e0 });
		return function (t) {
			var b = i(t);
			return arc(b);
		};
	}

	function textTween(d, i) {
		var a;
		if (oldPieData[i]) {
			a = (oldPieData[i].startAngle + oldPieData[i].endAngle - Math.PI) / 2;
		} else if (!(oldPieData[i]) && oldPieData[i - 1]) {
			a = (oldPieData[i - 1].startAngle + oldPieData[i - 1].endAngle - Math.PI) / 2;
		} else if (!(oldPieData[i - 1]) && oldPieData.length > 0) {
			a = (oldPieData[oldPieData.length - 1].startAngle + oldPieData[oldPieData.length - 1].endAngle - Math.PI) / 2;
		} else {
			a = 0;
		}
		var b = (d.startAngle + d.endAngle - Math.PI) / 2;

		var fn = d3.interpolateNumber(a, b);
		return function (t) {
			var val = fn(t);
			return "translate(" + Math.cos(val) * (r + textOffset) + "," + Math.sin(val) * (r + textOffset) + ")";
		};
	}

}

///////////////////////////////////////////////////////////
// PUBLIC FUNCIONTS ////////////////////////////////////
///////////////////////////////////////////////////////////


PieChart.prototype.setUrlParams = function (url_params) {
	this.url_params = url_params;
	this.forceUpdate();
}

PieChart.prototype.forceUpdate = function (url_params) {
	this.stopInterval();
	this.update();
	this.startInterval();
}

PieChart.prototype.setInterval = function (p_pieInterval) {
	this.pieInterval = p_pieInterval;
}

PieChart.prototype.stopInterval = function () {
	//disabled graph interval
	clearInterval(this.pieInterval);
}

PieChart.prototype.startInterval = function () {
	this.pieInterval = setInterval(this.update(), this.refresh)
}
///////////////////////////////////////////////////////////
// INIT FUNCIONTS ////////////////////////////////////
///////////////////////////////////////////////////////////

function create_pie_chart(name, units) {
	var w = 500; //380 - Please keep in sync with pie-chart.css
	var h = 325; //280
	var ir = 52; //45
	var textOffset = 14;
	var tweenDuration = 250;
	var r = 116; //100;

	if ($(name).hasClass("pie-chart-small")) {
		w = 330;
		h = 250;
		r = w / 5 + 15;
		ir = r / 2;
	}

	var lines, valueLabels, nameLabels;

	//D3 helper function to populate pie slice parameters from array data
	var donut = d3.layout.pie().value(function (d) {
		if (d.value == 0) { d.value = 1; } // Force to 1, in order to update the graph
		return d.value;
	});

	//D3 helper function to create colors from an ordinal scale
	var color = d3.scale.category20();

	//D3 helper function to draw arcs, populates parameter "d" in path object
	var arc = d3.svg.arc()
		.startAngle(function (d) { return d.startAngle; })
		.endAngle(function (d) { return d.endAngle; })
		.innerRadius(ir)
		.outerRadius(r);

	///////////////////////////////////////////////////////////
	// CREATE VIS & GROUPS ////////////////////////////////////
	///////////////////////////////////////////////////////////

	var vis = d3.select(name).append("svg:svg")
		.attr("width", w)
		.attr("height", h)
		.attr("viewBox", "0 0 " + w + " " + h)
		.attr("preserveAspectRatio", "xMidYMid");

	//GROUP FOR ARCS/PATHS
	var arc_group = vis.append("svg:g")
		.attr("class", "arc")
		.attr("transform", "translate(" + (w / 2) + "," + (h / 2) + ")");

	//GROUP FOR LABELS
	var label_group = vis.append("svg:g")
		.attr("class", "label_group")
		.attr("transform", "translate(" + (w / 2) + "," + (h / 2) + ")");

	//GROUP FOR CENTER TEXT
	var center_group = vis.append("svg:g")
		.attr("class", "center_group")
		.attr("transform", "translate(" + (w / 2) + "," + (h / 2) + ")");

	//PLACEHOLDER GRAY CIRCLE
	var paths = arc_group.append("svg:circle")
		.attr("fill", "#EFEFEF")
		.attr("r", r);

	///////////////////////////////////////////////////////////
	// CENTER TEXT ////////////////////////////////////////////
	///////////////////////////////////////////////////////////

	//WHITE CIRCLE BEHIND LABELS
	var whiteCircle = center_group.append("svg:circle")
		.attr("fill", "white")
		.attr("r", ir);

	var totalUnits = null;
	var totalLabel = null;
	var totalValue = null;

	if (units) {
		// "TOTAL" LABEL
		totalLabel = center_group.append("svg:text")
			.attr("class", "label")
			.attr("dy", -15)
			.attr("text-anchor", "middle") // text-align: right
			.text("TOTAL");

		//TOTAL TRAFFIC VALUE
		totalValue = center_group.append("svg:text")
			.attr("class", "total")
			.attr("dy", 7)
			.attr("text-anchor", "middle") // text-align: right
			.text("Waiting...");

		//UNITS LABEL
		totalUnits = center_group.append("svg:text")
			.attr("class", "units")
			.attr("dy", 21)
			.attr("text-anchor", "middle") // text-align: right
			.text(units);
	}

	return ([arc_group, donut, totalValue, totalUnits, color, tweenDuration, arc, label_group, center_group, r, textOffset]);
}
