(function() {
  'use strict';

  angular.module('kubernetesApp.components.dashboard')
      .directive('d3MinionBarGauge', [
        'd3DashboardService',
        function(d3DashboardService) {

          return {
            restrict: 'E',
            scope: {
              data: '=',
              thickness: '@',
              graphWidth: '@',
              graphHeight: '@'

            },
            link: function(scope, element, attrs) {

              var draw = function(d3) {
                var svg = d3.select("svg.chart");
                var legendSvg = d3.select("svg.legend");
                window.onresize = function() { return scope.$apply(); };

                scope.$watch(function() { return angular.element(window)[0].innerWidth; },
                             function() { return scope.render(scope.data); });

                scope.$watch('data', function(newVals, oldVals) {
                  return initOrUpdate(newVals, oldVals);

                }, true);

                function initOrUpdate(newVals, oldVals) {
                  if (oldVals === null || oldVals === undefined) {
                    return scope.render(newVals);
                  } else {
                    return update(oldVals, newVals);
                  }
                }

                var textOffset = 10;
                var el = null;
                var radius = 100;
                var oldData = [];

                function init(options) {
                  var clone = options.data;
                  var preparedData = setData(clone);
                  setup(preparedData, options.width, options.height);
                }

                function setup(data, w, h) {
                  svg = d3.select(element[0]).append("svg").attr("width", "100%");

                  legendSvg = d3.select(element[0]).append("svg").attr("width", "100%");

                  var chart = svg.attr("class", "chart")
                                  .attr("width", w)
                                  .attr("height", h - 25)
                                  .append("svg:g")
                                  .attr("class", "concentricchart")
                                  .attr("transform", "translate(" + ((w / 2)) + "," + h / 4 + ")");

                  var legend = legendSvg.attr("class", "legend").attr("width", w);

                  radius = Math.min(w, h) / 2;

                  var hostName = legendSvg.append("text")
                                     .attr("class", "hostName")
                                     .attr("transform", "translate(" + ((w - 120) / 2) + "," + 15 + ")");

                  var label_legend_area = legendSvg.append("svg:g")
                                              .attr("class", "label_legend_area")
                                              .attr("transform", "translate(" + ((w - 215) / 2) + "," + 35 + ")");

                  var legend_group = label_legend_area.append("svg:g").attr("class", "legend_group");

                  var label_group = label_legend_area.append("svg:g")
                                        .attr("class", "label_group")
                                        .attr("transform", "translate(" + 25 + "," + 11 + ")");

                  var stats_group = label_legend_area.append("svg:g")
                                        .attr("class", "stats_group")
                                        .attr("transform", "translate(" + 115 + "," + 11 + ")");

                  var path_group = chart.append("svg:g")
                                       .attr("class", "path_group")
                                       .attr("transform", "translate(0," + (h / 4) + ")");
                  var value_group = chart.append("svg:g")
                                        .attr("class", "value_group")
                                        .attr("transform", "translate(" + -(w * 0.205) + "," + -(h * 0.10) + ")");
                  generateArcs(chart, data);
                }

                function update(_oldData, _newData) {
                  if (_newData === undefined || _newData === null) {
                    return;
                  }

                  var clone = jQuery.extend(true, {}, _newData);
                  var cloneOld = jQuery.extend(true, {}, _oldData);
                  var preparedData = setData(clone);
                  oldData = setData(cloneOld);
                  animate(preparedData);
                }

                function animate(data) { generateArcs(null, data); }

                function setData(data) {
                  var diameter = 2 * Math.PI * radius;
                  var localData = [];

                  $.each(data[0].segments, function(ri, value) {

                    function calcAngles(v) {
                      var segmentValueSum = 200;
                      if (v > segmentValueSum) {
                        v = segmentValueSum;
                      }

                      var segmentValue = v;
                      var fraction = segmentValue / segmentValueSum;
                      var arcBatchLength = fraction * 4 * Math.PI;
                      var arcPartition = arcBatchLength;
                      var startAngle = Math.PI * 2;
                      var endAngle = startAngle + arcPartition;

                      return {
                        startAngle: startAngle,
                        endAngle: endAngle
                      };
                    }

                    var valueData = calcAngles(value.value);
                    data[0].segments[ri].startAngle = valueData.startAngle;
                    data[0].segments[ri].endAngle = valueData.endAngle;

                    var maxData = value.maxData;
                    var maxTickData = calcAngles(maxData.maxValue + 0.2);
                    data[0].segments[ri].maxTickStartAngle = maxTickData.startAngle;
                    data[0].segments[ri].maxTickEndAngle = maxTickData.endAngle;

                    var maxArcData = calcAngles(maxData.maxValue);
                    data[0].segments[ri].maxArcStartAngle = maxArcData.startAngle;
                    data[0].segments[ri].maxArcEndAngle = maxArcData.endAngle;

                    data[0].segments[ri].index = ri;
                  });
                  localData.push(data[0].segments);
                  return localData[0];
                }

                function generateArcs(_svg, data) {
                  var chart = svg;
                  var transitionTime = 750;
                  $.each(data, function(index, value) {
                    if (oldData[index] !== undefined) {
                      data[index].previousEndAngle = oldData[index].endAngle;
                    } else {
                      data[index].previousEndAngle = 0;
                    }
                  });
                  var thickness = parseInt(scope.thickness, 10);
                  var ir = (parseInt(scope.graphWidth, 10) / 3);
                  var path_group = svg.select('.path_group');
                  var arc_group = path_group.selectAll(".arc_group").data(data);
                  var arcEnter = arc_group.enter().append("g").attr("class", "arc_group");

                  arcEnter.append("path").attr("class", "bg-circle").attr("d", getBackgroundArc(thickness, ir));

                  arcEnter.append("path")
                      .attr("class", function(d, i) { return 'max_tick_arc ' + d.maxData.maxTickClassNames; });

                  arcEnter.append("path")
                      .attr("class", function(d, i) { return 'max_bg_arc ' + d.maxData.maxClassNames; });

                  arcEnter.append("path").attr("class", function(d, i) { return 'value_arc ' + d.classNames; });

                  var max_tick_arc = arc_group.select(".max_tick_arc");

                  max_tick_arc.transition()
                      .attr("class", function(d, i) { return 'max_tick_arc ' + d.maxData.maxTickClassNames; })
                      .attr("d", function(d) {
                        var arc = maxArc(thickness, ir);
                        arc.startAngle(d.maxTickStartAngle);
                        arc.endAngle(d.maxTickEndAngle);
                        return arc(d);
                      });

                  var max_bg_arc = arc_group.select(".max_bg_arc");

                  max_bg_arc.transition()
                      .attr("class", function(d, i) { return 'max_bg_arc ' + d.maxData.maxClassNames; })
                      .attr("d", function(d) {
                        var arc = maxArc(thickness, ir);
                        arc.startAngle(d.maxArcStartAngle);
                        arc.endAngle(d.maxArcEndAngle);
                        return arc(d);
                      });

                  var value_arc = arc_group.select(".value_arc");

                  value_arc.transition().ease("exp").attr("class", function(d, i) {
                    return 'value_arc ' + d.classNames;
                  }).duration(transitionTime).attrTween("d", function(d) { return arcTween(d, thickness, ir); });

                  arc_group.exit()
                      .select(".value_arc")
                      .transition()
                      .ease("exp")
                      .duration(transitionTime)
                      .attrTween("d", function(d) { return arcTween(d, thickness, ir); })
                      .remove();

                  drawLabels(chart, data, ir, thickness);
                  buildLegend(chart, data);
                }

                function arcTween(b, thickness, ir) {
                  var prev = JSON.parse(JSON.stringify(b));
                  prev.endAngle = b.previousEndAngle;
                  var i = d3.interpolate(prev, b);
                  return function(t) { return getArc(thickness, ir)(i(t)); };
                }

                function maxArc(thickness, ir) {
                  var arc = d3.svg.arc().innerRadius(function(d) {
                    return getRadiusRing(ir, d.index);
                  }).outerRadius(function(d) { return getRadiusRing(ir + thickness, d.index); });
                  return arc;
                }

                function drawLabels(chart, data, ir, thickness) {
                  svg.select('.value_group').selectAll("*").remove();
                  var counts = data.length;
                  var value_group = chart.select('.value_group');
                  var valueLabels = value_group.selectAll("text.value").data(data);
                  valueLabels.enter()
                      .append("svg:text")
                      .attr("class", "value")
                      .attr("dx", function(d, i) { return 68; })
                      .attr("dy", function(d, i) { return (thickness + 3) * i; })
                      .attr("text-anchor", function(d) { return "start"; })
                      .text(function(d) { return d.value; });
                  valueLabels.transition().duration(300).attrTween(
                      "d", function(d) { return arcTween(d, thickness, ir); });
                  valueLabels.exit().remove();
                }

                function buildLegend(chart, data) {
                  var svg = legendSvg;
                  svg.select('.label_group').selectAll("*").remove();
                  svg.select('.legend_group').selectAll("*").remove();
                  svg.select('.stats_group').selectAll("*").remove();

                  var host_name = svg.select('.hostName');
                  var label_group = svg.select('.label_group');
                  var stats_group = svg.select('.stats_group');

                  host_name.text(data[0].hostName);

                  host_name = svg.selectAll("text.hostName").data(data);

                  host_name.attr("text-anchor", function(d) { return "start"; })
                      .text(function(d) { return d.hostName; });
                  host_name.exit().remove();

                  var labels = label_group.selectAll("text.labels").data(data);
                  labels.enter()
                      .append("svg:text")
                      .attr("class", "labels")
                      .attr("dy", function(d, i) { return 19 * i; })
                      .attr("text-anchor", function(d) { return "start"; })
                      .text(function(d) { return d.label; });
                  labels.exit().remove();

                  var stats = stats_group.selectAll("text.stats").data(data);
                  stats.enter()
                      .append("svg:text")
                      .attr("class", "stats")
                      .attr("dy", function(d, i) { return 19 * i; })
                      .attr("text-anchor", function(d) { return "start"; })
                      .text(function(d) { return d.stats; });
                  stats.exit().remove();

                  var legend_group = svg.select('.legend_group');
                  var legend = legend_group.selectAll("rect").data(data);
                  legend.enter()
                      .append("svg:rect")
                      .attr("x", 2)
                      .attr("y", function(d, i) { return 19 * i; })
                      .attr("width", 13)
                      .attr("height", 13)
                      .attr("class", function(d, i) { return "rect " + d.classNames; });

                  legend.exit().remove();
                }

                function getRadiusRing(ir, i) { return ir - (i * 20); }

                function getArc(thickness, ir) {
                  var arc = d3.svg.arc()
                                .innerRadius(function(d) { return getRadiusRing(ir, d.index); })
                                .outerRadius(function(d) { return getRadiusRing(ir + thickness, d.index); })
                                .startAngle(function(d, i) { return d.startAngle; })
                                .endAngle(function(d, i) { return d.endAngle; });
                  return arc;
                }

                function getBackgroundArc(thickness, ir) {
                  var arc = d3.svg.arc()
                                .innerRadius(function(d) { return getRadiusRing(ir, d.index); })
                                .outerRadius(function(d) { return getRadiusRing(ir + thickness, d.index); })
                                .startAngle(0)
                                .endAngle(function() { return 2 * Math.PI; });
                  return arc;
                }

                scope.render = function(data) {
                  if (data === undefined || data === null) {
                    return;
                  }

                  d3.select(element[0]).select("svg.chart").remove();
                  d3.select(element[0]).select("svg.legend").remove();

                  var graph = $(element[0]);
                  var w = scope.graphWidth;
                  var h = scope.graphHeight;

                  var options = {
                    data: data,
                    width: w,
                    height: h
                  };

                  init(options);
                };
              };
              d3DashboardService.d3().then(draw);
            }
          };
        }
      ]);
}());
