/*\
title: $:/plugins/tiddlywiki/d3/cloudwidget.js
type: application/javascript
module-type: widget

A widget for displaying word clouds. Derived from https://github.com/jasondavies/d3-cloud

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

var Widget = require("$:/core/modules/widgets/widget.js").widget,
	d3 = require("$:/plugins/tiddlywiki/d3/d3.js").d3;

if($tw.browser) {
	// Frightful hack to give the cloud plugin the global d3 variable it needs
	window.d3 = d3;
	d3.layout.cloud  = require("$:/plugins/tiddlywiki/d3/d3.layout.cloud.js").cloud;
}

var CloudWidget = function(parseTreeNode,options) {
	this.initialise(parseTreeNode,options);
};

/*
Inherit from the base widget class
*/
CloudWidget.prototype = new Widget();

/*
Render this widget into the DOM
*/
CloudWidget.prototype.render = function(parent,nextSibling) {
	// Save the parent dom node
	this.parentDomNode = parent;
	// Compute our attributes
	this.computeAttributes();
	// Execute our logic
	this.execute();
	// Create the chart
	var chart = this.createChart(parent,nextSibling);
	this.updateChart = chart.updateChart;
	if(this.updateChart) {
		this.updateChart();
	}
	// Insert the chart into the DOM and render any children
	parent.insertBefore(chart.domNode,nextSibling);
	this.domNodes.push(chart.domNode);
};

CloudWidget.prototype.createChart = function(parent,nextSibling) {
	var self = this,
		fill = d3.scale.category20(),
		data = this.wiki.getTiddlerData(this.cloudData);
	// Use dummy data if none provided
	if(!data) {
		data = "This word cloud does not have any data in it".split(" ").map(function(d) {
			return {text: d, size: 10 + Math.random() * 90};
		});
	}
	// Create the svg element
	var svgElement = d3.select(parent).insert("svg",function() {return nextSibling;})
		.attr("width", 600)
		.attr("height", 400);
	// Create the main group
	var mainGroup = svgElement
		.append("g")
		.attr("transform", "translate(300,200)");
	// Create the layout
	var layout = d3.layout.cloud().size([600, 400])
		.words(data)
		.padding(5)
		.rotate(function() { return ~~(Math.random() * 5) * 30 - 60; })
		.font("Impact")
		.fontSize(function(d) { return d.size*2; })
		.on("end", draw)
		.start();
	// Function to draw all the words
	function draw(words) {
		mainGroup.selectAll("text")
			.data(words)
			.enter().append("text")
			.style("font-size", function(d) { return d.size + "px"; })
			.style("font-family", "Impact")
			.style("fill", function(d, i) { return fill(i); })
			.attr("text-anchor", "middle")
			.attr("transform", function(d) {
				return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
			})
			.text(function(d) { return d.text; });
	}
	function updateChart() {
		layout.spiral(self.spiral);
	}
	return {
		domNode: svgElement[0][0],
		updateChart: updateChart
	};
};

/*
Compute the internal state of the widget
*/
CloudWidget.prototype.execute = function() {
	// Get the parameters from the attributes
	this.cloudData = this.getAttribute("data");
	this.cloudSpiral = this.getAttribute("spiral","archimedean");
};

/*
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
*/
CloudWidget.prototype.refresh = function(changedTiddlers) {
	var changedAttributes = this.computeAttributes();
	if(changedAttributes.data || changedTiddlers[this.cloudData]) {
		this.refreshSelf();
		return true;
	} else if(changedAttributes.spiral) {
		this.execute();
		if(this.updateChart) {
			this.updateChart();
		}
		return true;
	}
	return false;
};

exports.d3cloud = CloudWidget;

})();
