'use strict';

angular.module('cs.tree', []).controller('TreeController', ['$scope', '$timeout', '$window',
	function($scope, $timeout, $window) {

		$scope.maxHeight = $window.innerHeight * 0.95;
		$scope.zoomEnabled = false;
		$scope.currentDepth = 0;
		$scope.selectNode = function(d) {
			if ($scope.tabData.node) {
				$scope.tabData.node.isSelected = false;
			}
			updateNode(d);
		};

		function updateNode(d) {
			if (d && d.name !== 'Customer' && d.name !== 'Customer ID' && d.name !== 'Anonymous ID') {
				d.isSelected = true;
				$scope.tabData.node = d;
				$scope.tabData.timeStarted = d.subheading;
				if (d.type === 'Service') {
					$scope.tabData.id = d.service_id;
					$scope.tabData.type = d.service_type;
					$scope.tabData.taskAddable = true;
					$scope.tabData.stateAddable = true;
				} else if (d.type === 'State') {
					$scope.tabData.id = d.state_id;
					$scope.tabData.type = d.state_type;
					$scope.tabData.taskAddable = true;
					$scope.tabData.stateAddable = false;
				} else if (d.type === 'Task') {
					$scope.tabData.id = d.task_id;
					$scope.tabData.type = d.task_type;
					$scope.tabData.taskAddable = false;
					$scope.tabData.stateAddable = false;
				}
				if (d.completed) {
					$scope.tabData.completed = true;
					$scope.tabData.timeCompleted = d.completed.timestamp;
				} else {
					$scope.tabData.completed = false;
					$scope.tabData.timeCompleted = '';
				}
			}
		}

		$scope.$watchCollection(function() {
				return $scope.tabData.node;
			},
			updateNode)

		$scope.enableZoom = function(event) {
			if (event.keyCode == 91 || event.keyCode == 224 || event.keyCode == 17) {
				$scope.zoomEnabled = true;
			}
		};

		$scope.disableZoom = function(event) {
			if (event.keyCode == 91 || event.keyCode == 224 || event.keyCode == 17) {
				$scope.zoomEnabled = false;
			}
		};

		$scope.openCounter = [0, 0, 0];

	}
])
	.directive('servicetree', function() {
		return {
			restrict: 'A',
			link: function(scope, ele) {
				scope.$watch(function() {
						return ele.width();
					},
					function() {
						scope.heightStyle = {
							'min-height': Math.min(ele.width() * 1.6, scope.maxHeight)
						};
						scope.update(root = scope.tabData.data)
					});
				var diameter, height, i = 0,
					root, baseScale = 0.4,
					zoomScale = 10,
					depthmod = 0;

				var zoom = d3.behavior.zoom().scaleExtent([0, 50]).on('zoom', zoomed);
				var removeZoom = d3.behavior.zoom().scaleExtent([0, 50]).on('zoom', null);

				var diagonal = d3.svg.diagonal.radial().projection(
					function(d) {
						return [d.y, d.x / 180 * Math.PI];
					});

				var svgContainer = d3.select(ele[0]);
				var svg = svgContainer.append('g');

				var tree;
				scope.update = function(source) {
					diameter = $(svgContainer[0]).parent().width();
					height = $(svgContainer[0]).parent().height();

					svgContainer.style('width', diameter + 'px').style('height', height + 'px');

					if (!source) {
						return;
					}

					zoom.scaleExtent([(diameter / 2 - 60) / ((scope.tabData.maxChildren + 2) * Math.max(scope.currentDepth, 1) * 20), 20]);

					if (scope.resetZoom) {
						zoom.translate([diameter / 2, diameter / 2]);
						zoom.scale((diameter / 2 - 60) / ((scope.tabData.maxChildren + 2) * Math.max(scope.currentDepth, 1) * 10));
						svg.attr('width', diameter).style('height', height)
							.attr('transform', 'translate(' +
								diameter / 2 + ',' + diameter / 2 + ')scale(' + (diameter / 2 - 60) / ((scope.tabData.maxChildren + 2) * Math.max(scope.currentDepth, 1) * 10) + ')');
						scope.resetZoom = false;
					}
					tree = d3.layout.tree().size(
						[360, ((scope.tabData.maxChildren + 2) * Math.max(scope.currentDepth, 1)) * 10]);

					if (source.children && source.children.length > 1) {
						tree.separation(function(a, b) {
							return (a.parent === b.parent ? 1 : 2) / a.depth;
						});
					} else {
						tree.separation(function() {
							return 1;
						});
					}
					var nodes = tree.nodes(source),
						links = tree.links(nodes);

					var allNodes = svg.selectAll('.node').data(nodes,
						function(d) {
							return d.id || (d.id = ++i);
						});

					var allLinks = svg.selectAll('.link')
						.data(links, function(d) {
							return d.target.id;
						});

					allLinks.enter()
						.append('path')
						.attr('class', 'link')
						.attr('d', function(d) {
							var o;
							if (scope.clicked) {
								o = {
									x: scope.clicked.x,
									y: scope.clicked.y
								};
							} else {
								o = {
									x: d.target.x,
									y: d.target.y
								};
							}
							return diagonal({
								source: o,
								target: o
							});
						});

					var node = allNodes
						.enter()
						.append('g')
						.attr('transform',
							function(d) {
								if (scope.clicked) {
									return 'rotate(' + (scope.clicked.x - 90) + ')translate(' + scope.clicked.y + ')scale(0)';
								}
								return 'rotate(' + (d.x - 90) + ')translate(' + d.y + ')scale(0)';
							})
						.attr('class', 'node');


					node.append('text')
						.attr('text-anchor',
							function() {
								return 'middle';
							})
						.attr('transform', function(d) {
							return 'rotate(' + (-d.x + 90) + ')';
						})
						.text(function(d) {
							return d.name + completedIcon(d);
						})
						.style('cursor', 'pointer')
						.style('pointer-events', 'all')
						.style('font-family', 'ark-icons')
						.on('click', scope.click)
						.on('dblclick', scope.dblclick);

					node.append('text').attr('text-anchor',
						function() {
							return 'middle';
						})
						.attr('transform',
							function(d) {
								return 'rotate(' + (-d.x + 90) + ')translate(0,10)';
							})
						.text(
							function(d) {
								return d.subheading ? d.subheading : '';
							})
						.style('cursor', 'pointer')
						.style('pointer-events', 'all')
						.on('click', scope.click)
						.on('dblclick', scope.dblclick);

					var ellipse = node.insert('ellipse', 'text')
						.attr('rx',
							function(d, i) {
								return Math.max(allNodes.selectAll('text')[i][0].getComputedTextLength(),
									allNodes.selectAll('text')[i][1].getComputedTextLength()) / 2 + 15;
							})
						.attr('ry',
							function(d, i) {
								return node.select('ellipse')[0][i].rx.baseVal.value / 1.6;
							})
						.attr('transform',
							function(d) {
								return 'rotate(' + (-d.x + 90) + ')';
							})
						.style('cursor', 'pointer')
						.style('fill', fillColorize)
						.style('stroke', strokeColorize)
						.on('click', scope.click)
						.on('dblclick', scope.dblclick);

					var nodeUpdate = allNodes.transition()
						.duration(1000)
						.attr("transform", function(d) {
							return 'rotate(' + (d.x - 90) + ')translate(' + d.y + ')';
						});

					nodeUpdate.selectAll('text').attr('transform', function(d) {
						if (d.depth != 0) {
							if (this.textContent === d.subheading) {
								return 'rotate(' + (-d.x + 90) + ')scale(' + baseScale + ')translate(0,10)';
							} else {
								return 'rotate(' + (-d.x + 90) + ')scale(' + baseScale + ')';
							}
						} else if (this.textContent === d.subheading) {
							return 'rotate(-90)scale(' + baseScale + ')translate(0,10)';
						} else {
							return 'rotate(-90)scale(' + baseScale + ')';
						}
					});

					nodeUpdate.select('ellipse').attr('transform', function(d) {
						return (d.depth == 0) ? 'rotate(-90)scale(' + baseScale + ')' : 'rotate(' + (-d.x + 90) + ')scale(' + baseScale + ')';
					});

					var nodeExit = allNodes.exit().transition()
						.duration(1000)
						.attr("transform", function(d) {
							if (scope.clicked == d) {
								scope.clicked = null;
							} else if (scope.clicked) {
								return 'rotate(' + (scope.clicked.x - 90) + ')translate(' + scope.clicked.y + ')scale(0)';
							} else if (d.parent) {
								return 'rotate(' + (d.parent.x - 90) + ')translate(' + d.parent.y + ')scale(0)';
							}
							return 'rotate(' + (source.x - 90) + ')translate(' + source.y + ')scale(0)';
						})
						.remove();

					allLinks.transition()
						.duration(1000)
						.attr("d", diagonal)
						.each(function(d) {
							if (this.parentNode.firstChild) {
								this.parentNode.insertBefore(this, this.parentNode.firstChild);
							}
						});

					allLinks.exit().transition()
						.duration(1000)
						.attr("d", function(d) {
							var o;
							if (scope.clicked) {
								o = {
									x: scope.clicked.x,
									y: scope.clicked.y
								};
							} else if (d.target.parent) {
								o = {
									x: d.target.parent.x,
									y: d.target.parent.y
								};
							} else {
								o = {
									x: source.x,
									y: source.y
								};
							}
							return diagonal({
								source: o,
								target: o
							});
						})
						.remove();

				};

				scope.tabData.refreshTree = function() {
					var data = scope.tabData.node;
					if (data.type === 'Service') {
						svg.selectAll('.node')
							.filter(
								function(d) {
									return d.service_id === data.service_id;
								})
							.each(scope.click);
					} else if (data.type === 'Task') {
						svg.selectAll('.node')
							.filter(
								function(d) {
									return d.task_id === data.task_id;
								})
							.each(scope.click);
					} else if (data.type === 'State') {
						svg.selectAll('.node')
							.filter(
								function(d) {
									return d.state_id === data.state_id;
								})
							.each(scope.click);
					}
				};

				scope.$watch(function() {
					return scope.tabData.data;
				}, function() {
					scope.resetZoom = true;
					scope.clicked = null;
					scope.currentDepth = 0;
					scope.openCounter = [0, 0, 0];
					scope.update(root = scope.tabData.data, ele);
				});

				function zoomed() {
					svg.attr('transform',
						'translate(' + d3.event.translate[0] + ',' +
						d3.event.translate[1] + ')scale(' + d3.event.scale + ')');
				}

				function toggleZoom() {
					if (scope.zoomEnabled) {
						svgContainer.call(zoom);
					} else {
						svgContainer.call(removeZoom);
					}
				}

				scope.$watch(function() {
						return scope.zoomEnabled;
					},
					function() {
						toggleZoom();
					});

				scope.dblclick = function(d) {
					if (root != d) {
						depthmod = d.depth;
						scope.update(root = d, ele);
					} else {
						depthmod = 0;
						scope.update(root = scope.tabData.data, ele);
					}
				};

				scope.click = function(d) {
					scope.tabData.taskAddable = false;
					scope.tabData.stateAddable = false;
					scope.clicked = d;
					if (d.children) {
						scope.openCounter[d.depth + depthmod]--;
						if (scope.openCounter[d.depth + depthmod] <= 0) {
							scope.openCounter[d.depth + depthmod] = 0;
							scope.currentDepth--;
							for (var i = d.depth + depthmod + 1; i < scope.openCounter.length; i++) {
								if (scope.openCounter[i] <= 0) {
									scope.openCounter[i] = 0;
									break;
								}
								scope.currentDepth--;
								scope.openCounter[i] = 0;
							}
						}
						d.hideChildren = d.children;
						d.children = null;
					} else if (d.hideChildren) {
						if (scope.openCounter[d.depth + depthmod] == 0) {
							scope.currentDepth++;
						}
						scope.openCounter[d.depth + depthmod]++;
						d.children = d.hideChildren;
					}
					if (d.name !== 'Customer' && d.name !== 'Customer ID') {
						if (scope.tabData.node) {
							scope.tabData.node.stroke = '';
						}
						d.stroke = 'red';
						scope.selectNode(d);
						svg.selectAll('ellipse').style('stroke', strokeColorize);
					}
					svg.selectAll('ellipse').style('fill', fillColorize);
					scope.update(root, ele);
					scope.$apply();
				};

				function completedIcon(d) {
					if (d.completed) {
						return ' \ue065';
					}
					return '';
				}

				function fillColorize(d) {
					if (!d.children && d.hideChildren) {
						switch (d.type) {
							case 'Service':
								return '#FFF0E0';
								break;
							case 'Task':
								return '#DEFADE';
								break;
							case 'State':
								return '#F3FFFF';
								break;
							default:
								return '#FFFFB2';
						}
					} else {
						switch (d.type) {
							case 'Service':
								return '#FFCC99';
								break;
							case 'Task':
								return '#90EE90';
								break;
							case 'State':
								return '#E0FFFF';
								break;
							default:
								return 'Yellow';
						}
					}
				}

				function strokeColorize(d) {
					if (d.stroke) {
						return d.stroke;
					}
				}
			}
		};
	});
