var __extends = this.__extends || function (d, b) {
	for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
	function __() { this.constructor = d; }
	__.prototype = b.prototype;
	d.prototype = new __();
};

var FD;
(function (FD) {
	var TreeMapVisualisation = (function (_super) {
		__extends(TreeMapVisualisation, _super);
		function TreeMapVisualisation(debug, fluidDiagram) {
			_super.call(this, debug, fluidDiagram);
			this.rootNode = null;
			this.leaves = [];
		}
		
		TreeMapVisualisation.prototype.visualise = function() {
			this.backgroundColor = 0xffffff;

			this.rootNode = this.parseData(null, this.nodes[0]);
			this.rootNode.sort();
			this.rootNode.frame.initialize(0, 0, this.width, this.height);

			/*var totalWeight = this.rootNode.getWeight();

			this.leaves.map(function(leaf) {
				leaf.weight /= totalWeight;
			});*/

			this.process(this.rootNode);

			this.draw(this.leaves);

			$('body').append('<pre>' + this.print(this.rootNode) + '</pre>');
		};

		TreeMapVisualisation.prototype.print = function(node, indent) {
			indent = indent || 1;
			var output = '';

			var i = Array(indent).join(0).split('').reduce(function(p) { return p + '  '; }, '');
			output += i + node.data + '[' + node.getWeight() + ']' + ' >> ' + node.frame.toString() + '\n';

			for(var child in node.children) {
				output += this.print(node.children[child], indent+1);
			}

			return output;
		};

		TreeMapVisualisation.prototype.draw = function(nodes) {
			for(var i = 0; i < nodes.length; i++) {
				var node = nodes[i];

				if(node.frame.isInitialized) this.drawRect(node.frame, node.parent.color);
				//console.log('//> ' + node.data + ' ## ' + node.frame.toString() + ' // ' + node.data);

				if(i == 9) return;
			}
		};

		TreeMapVisualisation.prototype.drawRect = function(frame, color) {
			var rectShape = new THREE.Shape();
			rectShape.moveTo(frame.x, frame.y);
			rectShape.lineTo(frame.x, frame.width);
			rectShape.lineTo(frame.height, frame.width);
			rectShape.lineTo(frame.height, frame.y);
			rectShape.lineTo(frame.x, frame.y);

			var rectGeom = new THREE.ShapeGeometry(rectShape);
			var rectMesh = new THREE.Mesh(rectGeom, new THREE.MeshBasicMaterial({ 
				color: color
			}));

			//this.fluidDiagrams.addSceneObject(rectMesh);

			edges = new THREE.EdgesHelper(rectMesh, 0x000000);
			this.fluidDiagrams.addSceneObject(edges);
		};

		TreeMapVisualisation.prototype.squarify = function(node, width, height) {
			if(node.isLeaf()) {
				node.frame.initialize(
					(node.parent === null ? 0 : node.parent.frame.x),
					(node.parent === null ? 0 : node.parent.frame.y),
					width,
					height
				);

				return;
			}

			if(node.children.length == 1) {
				node.children[0].frame.initialize(
					(node.children[0].parent === null ? 0 : node.children[0].parent.frame.x),
					(node.children[0].parent === null ? 0 : node.children[0].parent.frame.y),
					width,
					height
				);

				return;
			}

			var children = [];
			for(var child in node.children) {
				children.push({
					weight: node.children[child].getWeight(),
					obj: node.children[child]
				});
			}
			this.scaleWeights(children, width, height);

			children.push({
				weight: 0,
				obj: {data: null}
			});

			var vertical = height < width;
			var w = vertical ? height : width;
			var x = 0, y = 0;
			var rw = width;
			var rh = height;
			var row = [];

			while (children.length > 0) {
				var c = children[0];
				var r = c.weight;
				var s = this.sum(row);
				var min = this.min(row);
				var max = this.max(row);
				var wit = this.worst(s + r, Math.min(min, r), Math.max(max, r), w);
				var without = this.worst(s, min, max, w);

				console.log("c: " + c.obj.data);
				console.log("row: " + row.length);
				console.log("w: " + w);
				console.log("r: " + r);
				console.log("s: " + s);
				console.log("min: " + min);
				console.log("max: " + max);
				console.log("wit: " + wit);
				console.log("without: " + without);

				if (row.length === 0 || wit < without) {
					row.push(c);
					children.shift();
				}
				else {
					var rx = x;
					var ry = y;
					var z = s / w;
					var j;

					row.map(function(a) { console.log(a.obj.data); });
					console.log('-----');

					for (j = 0; j < row.length; ++j) {
						var d = row[j].weight / z;

						if(vertical) {
							row[j].obj.frame.initialize(
								row[j].obj.parent.frame.x + rx,
								row[j].obj.parent.frame.y + ry,
								z,
								d
							);
							ry = ry + d;
						}
						else {
							row[j].obj.frame.initialize(
								row[j].obj.parent.frame.x + rx,
								row[j].obj.parent.frame.y + ry,
								d,
								z
							);
							rx = rx + d;
						}

						if(row[j].obj.isLeaf()) { this.leaves.push(row[j].obj); }
					}
					
					if (vertical) {
						x = x + z;
						rw = rw - z;
					}
					else {
						y = y + z;
						rh = rh - z;
					}

					vertical = rh < rw;
					w = vertical ? rh : rw;
					row = [];
				}
			}

			console.log('######');
			row.map(function(a) { console.log(a.obj.data); });
		};

		TreeMapVisualisation.prototype.worst = function(s, min, max, w) {
			var a = 0;
			if(s !== 0) a = w * w * max / (s * s);

			var b = 0;
			if(min !== 0) b = s * s / (w * w * min);

			return Math.max(a, b);
		};

		TreeMapVisualisation.prototype.scaleWeights = function(nodes, width, height) {
			var scale = width * height / this.sum(nodes);
			for (var i = 0; i < nodes.length; i++) {
			    nodes[i].weight = scale * nodes[i].weight;
			}
		};

		TreeMapVisualisation.prototype.max = function(nodes) {
			if(nodes.length === 0) return 0;
			var weights = nodes.map(function(d) { return d.weight; });
			return Math.max.apply(Math, weights);
		};

		TreeMapVisualisation.prototype.min = function(nodes) {
			if(nodes.length === 0) return 0;
			var weights = nodes.map(function(d) { return d.weight; });
			return Math.min.apply(Math, weights);
		};

		TreeMapVisualisation.prototype.sum = function(nodes) {
			var total = 0;
			for(var i = 0; i < nodes.length; i++) {
				total += nodes[i].weight;
			}
			return total;
		};

		TreeMapVisualisation.prototype.process = function(rootNode) {
			var nodes = [];
			nodes.push(rootNode);

			while(nodes.length > 0) {
				var node = nodes.shift();

				if(node.isNode()) {
					this.squarify(node, node.frame.width, node.frame.height);

					if(node.hasChildren()) {
						nodes = nodes.concat(node.children);
					}
				}

				//console.log(node.data + ' // ' + node.frame.toString());
			}
		};

		TreeMapVisualisation.prototype.parseData = function(root, node) {
			var n;

			if(!node.children || node.children.length === 0) {
				n = new FD.TreeMapLeaf(node.name.trim(), node.size);
				//this.leaves.push(n);
			}
			else {
				n = new FD.TreeMapNode(node.name.trim());

				for(var child in node.children) {
					this.parseData(n, node.children[child]);
				}
			}

			if(root === null)
				return n;
			else
				return root.addNode(n);
		};

		return TreeMapVisualisation;
	})(FD.FDVisualisation);
	FD.TreeMapVisualisation = TreeMapVisualisation;
})(FD || (FD = {}));