text: define([
    'angular',
    'jquery',
    'kbn',
    'moment',
    'underscore'
  ],
  function (angular, $, kbn, moment, _) {
    'use strict';
  
    var module = angular.module('kibana.directives');
  
    module.directive('grafanaGraph', function($rootScope, dashboard) {
      return {
        restrict: 'A',
        template: '<div> </div>',
        link: function(scope, elem) {
          var data, plot, annotations;
          var hiddenData = {};
  
          scope.$on('refresh',function() {
            if (scope.otherPanelInFullscreenMode()) { return; }
            scope.get_data();
          });
  
          scope.$on('toggleLegend', function(e, series) {
            _.each(series, function(serie) {
              if (hiddenData[serie.alias]) {
                data.push(hiddenData[serie.alias]);
                delete hiddenData[serie.alias];
              }
            });
  
            render_panel();
          });
  
          // Receive render events
          scope.$on('render',function(event, renderData) {
            data = renderData || data;
            annotations = data.annotations;
            render_panel();
          });
  
          // Re-render if the window is resized
          angular.element(window).bind('resize', function() {
            render_panel();
          });
  
          function setElementHeight() {
            try {
              var height = scope.height || scope.panel.height || scope.row.height;
              if (_.isString(height)) {
                height = parseInt(height.replace('px', ''), 10);
              }
  
              height = height - 32; // subtract panel title bar
  
              if (scope.panel.legend.show) {
                height = height - 21; // subtract one line legend
              }
  
              elem.css('height', height + 'px');
  
              return true;
            } catch(e) { // IE throws errors sometimes
              return false;
            }
          }
  
          function shouldAbortRender() {
            if (!data) {
              return true;
            }
  
            if ($rootScope.fullscreen && !scope.fullscreen) {
              return true;
            }
  
            if (!setElementHeight()) { return true; }
  
            if (_.isString(data)) {
              render_panel_as_graphite_png(data);
              return true;
            }
          }
  
          // Function for rendering panel
          function render_panel() {
            if (shouldAbortRender()) {
              return;
            }
  
            var panel = scope.panel;
  
            _.each(_.keys(scope.hiddenSeries), function(seriesAlias) {
              var dataSeries = _.find(data, function(series) {
                return series.info.alias === seriesAlias;
              });
              if (dataSeries) {
                hiddenData[dataSeries.info.alias] = dataSeries;
                data = _.without(data, dataSeries);
              }
            });
  
            var stack = panel.stack ? true : null;
  
            // Populate element
            var options = {
              legend: { show: false },
              series: {
                stackpercent: panel.stack ? panel.percentage : false,
                stack: panel.percentage ? null : stack,
                lines:  {
                  show: panel.lines,
                  zero: false,
                  fill: panel.fill === 0 ? 0.001 : panel.fill/10,
                  lineWidth: panel.linewidth,
                  steps: panel.steppedLine
                },
                bars:   {
                  show: panel.bars,
                  fill: 1,
                  barWidth: 1,
                  zero: false,
                  lineWidth: 0
                },
                points: {
                  show: panel.points,
                  fill: 1,
                  fillColor: false,
                  radius: panel.pointradius
                },
                shadowSize: 1
              },
              yaxes: [],
              xaxis: {},
              grid: {
                markings: [],
                backgroundColor: null,
                borderWidth: 0,
                hoverable: true,
                color: '#c8c8c8'
              },
              selection: {
                mode: "x",
                color: '#666'
              }
            };
  
            for (var i = 0; i < data.length; i++) {
              var _d = data[i].getFlotPairs(panel.nullPointMode, panel.y_formats);
              data[i].data = _d;
            }
  
            if (panel.bars && data.length && data[0].info.timeStep) {
              options.series.bars.barWidth = data[0].info.timeStep / 1.5;
            }
  
            addTimeAxis(options);
            addGridThresholds(options, panel);
            addAnnotations(options);
            configureAxisOptions(data, options);
  
            plot = $.plot(elem, data, options);
  
            addAxisLabels();
          }
  
          function addTimeAxis(options) {
            var ticks = elem.width() / 100;
            var min = _.isUndefined(scope.range.from) ? null : scope.range.from.getTime();
            var max = _.isUndefined(scope.range.to) ? null : scope.range.to.getTime();
  
            options.xaxis = {
              timezone: dashboard.current.timezone,
              show: scope.panel['x-axis'],
              mode: "time",
              min: min,
              max: max,
              label: "Datetime",
              ticks: ticks,
              timeformat: time_format(scope.interval, ticks, min, max),
            };
          }
  
          function addGridThresholds(options, panel) {
            if (panel.grid.threshold1) {
              var limit1 = panel.grid.thresholdLine ? panel.grid.threshold1 : (panel.grid.threshold2 || null);
              options.grid.markings.push({
                yaxis: { from: panel.grid.threshold1, to: limit1 },
                color: panel.grid.threshold1Color
              });
  
              if (panel.grid.threshold2) {
                var limit2;
                if (panel.grid.thresholdLine) {
                  limit2 = panel.grid.threshold2;
                } else {
                  limit2 = panel.grid.threshold1 > panel.grid.threshold2 ?  -Infinity : +Infinity;
                }
                options.grid.markings.push({
                  yaxis: { from: panel.grid.threshold2, to: limit2 },
                  color: panel.grid.threshold2Color
                });
              }
            }
          }
  
          function addAnnotations(options) {
            if(!annotations || annotations.length === 0) {
              return;
            }
  
            var types = {};
  
            _.each(annotations, function(event) {
              if (!types[event.annotation.name]) {
                types[event.annotation.name] = {
                  level: _.keys(types).length + 1,
                  icon: {
                    icon: "icon-chevron-down",
                    size: event.annotation.iconSize,
                    color: event.annotation.iconColor,
                  }
                };
              }
  
              if (event.annotation.showLine) {
                options.grid.markings.push({
                  color: event.annotation.lineColor,
                  lineWidth: 1,
                  xaxis: { from: event.min, to: event.max }
                });
              }
            });
  
            options.events = {
              levels: _.keys(types).length + 1,
              data: annotations,
              types: types
            };
          }
  
          function addAxisLabels() {
            if (scope.panel.leftYAxisLabel) {
              elem.css('margin-left', '10px');
              var yaxisLabel = $("<div class='axisLabel yaxisLabel'></div>")
                .text(scope.panel.leftYAxisLabel)
                .appendTo(elem);
  
              yaxisLabel.css("margin-top", yaxisLabel.width() / 2 - 20);
            } else if (elem.css('margin-left')) {
              elem.css('margin-left', '');
            }
          }
  
          function configureAxisOptions(data, options) {
            var defaults = {
              position: 'left',
              show: scope.panel['y-axis'],
              min: scope.panel.grid.leftMin,
              max: scope.panel.percentage && scope.panel.stack ? 100 : scope.panel.grid.leftMax,
            };
  
            options.yaxes.push(defaults);
  
            if (_.findWhere(data, {yaxis: 2})) {
              var secondY = _.clone(defaults);
              secondY.position = 'right';
              secondY.min = scope.panel.grid.rightMin;
              secondY.max = scope.panel.percentage && scope.panel.stack ? 100 : scope.panel.grid.rightMax;
              options.yaxes.push(secondY);
              configureAxisMode(options.yaxes[1], scope.panel.y_formats[1]);
            }
  
            configureAxisMode(options.yaxes[0], scope.panel.y_formats[0]);
          }
  
          function configureAxisMode(axis, format) {
            if (format !== 'none') {
              axis.tickFormatter = kbn.getFormatFunction(format, 1);
            }
          }
  
          function time_format(interval, ticks, min, max) {
            if (min && max && ticks) {
              var secPerTick = ((max - min) / ticks) / 1000;
  
              if (secPerTick <= 45) {
                return "%H:%M:%S";
              }
              if (secPerTick <= 3600) {
                return "%H:%M";
              }
              if (secPerTick <= 80000) {
                return "%m/%d %H:%M";
              }
              if (secPerTick <= 2419200) {
                return "%m/%d";
              }
              return "%Y-%m";
            }
  
            return "%H:%M";
          }
  
          var $tooltip = $('<div>');
  
          elem.bind("plothover", function (event, pos, item) {
            var group, value, timestamp, seriesInfo, format;
  
            if (item) {
              seriesInfo = item.series.info;
              format = scope.panel.y_formats[seriesInfo.yaxis - 1];
  
              if (seriesInfo.alias) {
                group = '<small style="font-size:0.9em;">' +
                  '<i class="icon-circle" style="color:'+item.series.color+';"></i>' + ' ' +
                  (decodeURIComponent(seriesInfo.alias)) +
                '</small><br>';
              } else {
                group = kbn.query_color_dot(item.series.color, 15) + ' ';
              }
  
              if (scope.panel.stack && scope.panel.tooltip.value_type === 'individual') {
                value = item.datapoint[1] - item.datapoint[2];
              }
              else {
                value = item.datapoint[1];
              }
  
              value = kbn.getFormatFunction(format, 2)(value);
  
              timestamp = dashboard.current.timezone === 'browser' ?
                moment(item.datapoint[0]).format('YYYY-MM-DD HH:mm:ss') :
                moment.utc(item.datapoint[0]).format('YYYY-MM-DD HH:mm:ss');
              $tooltip
                .html(
                  group + value + " @ " + timestamp
                )
                .place_tt(pos.pageX, pos.pageY);
            } else {
              $tooltip.detach();
            }
          });
  
          function render_panel_as_graphite_png(url) {
            url += '&width=' + elem.width();
            url += '&height=' + elem.css('height').replace('px', '');
            url += '&bgcolor=1f1f1f'; // @grayDarker & @kibanaPanelBackground
            url += '&fgcolor=BBBFC2'; // @textColor & @grayLighter
            url += scope.panel.stack ? '&areaMode=stacked' : '';
            url += scope.panel.fill !== 0 ? ('&areaAlpha=' + (scope.panel.fill/10).toFixed(1)) : '';
            url += scope.panel.linewidth !== 0 ? '&lineWidth=' + scope.panel.linewidth : '';
            url += scope.panel.legend.show ? '&hideLegend=false' : '&hideLegend=true';
            url += scope.panel.grid.min !== null ? '&yMin=' + scope.panel.grid.min : '';
            url += scope.panel.grid.max !== null ? '&yMax=' + scope.panel.grid.max : '';
            url += scope.panel['x-axis'] ? '' : '&hideAxes=true';
            url += scope.panel['y-axis'] ? '' : '&hideYAxis=true';
  
            switch(scope.panel.y_formats[0]) {
            case 'bytes':
              url += '&yUnitSystem=binary';
              break;
            case 'bits':
              url += '&yUnitSystem=binary';
              break;
            case 'short':
              url += '&yUnitSystem=si';
              break;
            case 'none':
              url += '&yUnitSystem=none';
              break;
            }
  
            switch(scope.panel.nullPointMode) {
            case 'connected':
              url += '&lineMode=connected';
              break;
            case 'null':
              break; // graphite default lineMode
            case 'null as zero':
              url += "&drawNullAsZero=true";
              break;
            }
  
            url += scope.panel.steppedLine ? '&lineMode=staircase' : '';
  
            elem.html('<img src="' + url + '"></img>');
          }
  
          elem.bind("plotselected", function (event, ranges) {
            scope.$apply(function() {
              scope.filter.setTime({
                from  : moment.utc(ranges.xaxis.from).toDate(),
                to    : moment.utc(ranges.xaxis.to).toDate(),
              });
            });
          });
        }
      };
    });
  
  });
  