/**
 * echarts图表类：仪表盘
 *
 * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。
 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
 *
 */
module.exports = function (require) {
  var ChartBase = require('./base'); // 图形依赖


  var GaugePointerShape = require('../util/shape/GaugePointer');

  var TextShape = require('zrender/shape/Text');

  var LineShape = require('zrender/shape/Line');

  var RectangleShape = require('zrender/shape/Rectangle');

  var CircleShape = require('zrender/shape/Circle');

  var SectorShape = require('zrender/shape/Sector');

  var ecConfig = require('../config'); // 仪表盘默认参数


  ecConfig.gauge = {
    zlevel: 0,
    // 一级层叠
    z: 2,
    // 二级层叠
    center: ['50%', '50%'],
    // 默认全局居中
    clickable: true,
    legendHoverLink: true,
    radius: '75%',
    startAngle: 225,
    endAngle: -45,
    min: 0,
    // 最小值
    max: 100,
    // 最大值
    splitNumber: 10,
    // 分割段数，默认为10
    axisLine: {
      // 坐标轴线
      show: true,
      // 默认显示，属性show控制显示与否
      lineStyle: {
        // 属性lineStyle控制线条样式
        color: [[0.2, '#228b22'], [0.8, '#48b'], [1, '#ff4500']],
        width: 30
      }
    },
    axisTick: {
      // 坐标轴小标记
      show: true,
      // 属性show控制显示与否，默认不显示
      splitNumber: 5,
      // 每份split细分多少段
      length: 8,
      // 属性length控制线长
      lineStyle: {
        // 属性lineStyle控制线条样式
        color: '#eee',
        width: 1,
        type: 'solid'
      }
    },
    axisLabel: {
      // 坐标轴文本标签，详见axis.axisLabel
      show: true,
      // formatter: null,
      textStyle: {
        // 其余属性默认使用全局文本样式，详见TEXTSTYLE
        color: 'auto'
      }
    },
    splitLine: {
      // 分隔线
      show: true,
      // 默认显示，属性show控制显示与否
      length: 30,
      // 属性length控制线长
      lineStyle: {
        // 属性lineStyle（详见lineStyle）控制线条样式
        color: '#eee',
        width: 2,
        type: 'solid'
      }
    },
    pointer: {
      show: true,
      length: '80%',
      width: 8,
      color: 'auto'
    },
    title: {
      show: true,
      offsetCenter: [0, '-40%'],
      // x, y，单位px
      textStyle: {
        // 其余属性默认使用全局文本样式，详见TEXTSTYLE
        color: '#333',
        fontSize: 15
      }
    },
    detail: {
      show: true,
      backgroundColor: 'rgba(0,0,0,0)',
      borderWidth: 0,
      borderColor: '#ccc',
      width: 100,
      height: 40,
      offsetCenter: [0, '40%'],
      // x, y，单位px
      // formatter: null,
      textStyle: {
        // 其余属性默认使用全局文本样式，详见TEXTSTYLE
        color: 'auto',
        fontSize: 30
      }
    }
  };

  var ecData = require('../util/ecData');

  var accMath = require('../util/accMath');

  var zrUtil = require('zrender/tool/util');
  /**
   * 构造函数
   * @param {Object} messageCenter echart消息中心
   * @param {ZRender} zr zrender实例
   * @param {Object} series 数据
   * @param {Object} component 组件
   */


  function Gauge(ecTheme, messageCenter, zr, option, myChart) {
    // 图表基类
    ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
    this.refresh(option);
  }

  Gauge.prototype = {
    type: ecConfig.CHART_TYPE_GAUGE,

    /**
     * 绘制图形
     */
    _buildShape: function () {
      var series = this.series; // 复用参数索引

      this._paramsMap = {};
      this.selectedMap = {};

      for (var i = 0, l = series.length; i < l; i++) {
        if (series[i].type === ecConfig.CHART_TYPE_GAUGE) {
          //仪表图不用去legend 获取状态，默认这里给的true 
          this.selectedMap[series[i].name] = true;
          series[i] = this.reformOption(series[i]);
          this.legendHoverLink = series[i].legendHoverLink || this.legendHoverLink;

          this._buildSingleGauge(i);

          this.buildMark(i);
        }
      }

      this.addShapeList();
    },

    /**
     * 构建单个仪表盘
     *
     * @param {number} seriesIndex 系列索引
     */
    _buildSingleGauge: function (seriesIndex) {
      var serie = this.series[seriesIndex];
      this._paramsMap[seriesIndex] = {
        center: this.parseCenter(this.zr, serie.center),
        radius: this.parseRadius(this.zr, serie.radius),
        startAngle: serie.startAngle.toFixed(2) - 0,
        endAngle: serie.endAngle.toFixed(2) - 0
      };
      this._paramsMap[seriesIndex].totalAngle = this._paramsMap[seriesIndex].startAngle - this._paramsMap[seriesIndex].endAngle;

      this._colorMap(seriesIndex);

      this._buildAxisLine(seriesIndex);

      this._buildSplitLine(seriesIndex);

      this._buildAxisTick(seriesIndex);

      this._buildAxisLabel(seriesIndex);

      this._buildPointer(seriesIndex);

      this._buildTitle(seriesIndex);

      this._buildDetail(seriesIndex);
    },
    // 轴线
    _buildAxisLine: function (seriesIndex) {
      var serie = this.series[seriesIndex];

      if (!serie.axisLine.show) {
        return;
      }

      var min = serie.min;
      var total = serie.max - min;
      var params = this._paramsMap[seriesIndex];
      var center = params.center;
      var startAngle = params.startAngle;
      var totalAngle = params.totalAngle;
      var colorArray = params.colorArray;
      var lineStyle = serie.axisLine.lineStyle;
      var lineWidth = this.parsePercent(lineStyle.width, params.radius[1]);
      var r = params.radius[1];
      var r0 = r - lineWidth;
      var sectorShape;
      var lastAngle = startAngle;
      var newAngle;

      for (var i = 0, l = colorArray.length; i < l; i++) {
        newAngle = startAngle - totalAngle * (colorArray[i][0] - min) / total;
        sectorShape = this._getSector(center, r0, r, newAngle, // startAngle
        lastAngle, // endAngle
        colorArray[i][1], // color
        lineStyle, serie.zlevel, serie.z);
        lastAngle = newAngle;
        sectorShape._animationAdd = 'r';
        ecData.set(sectorShape, 'seriesIndex', seriesIndex);
        ecData.set(sectorShape, 'dataIndex', i);
        this.shapeList.push(sectorShape);
      }
    },
    // 坐标轴分割线
    _buildSplitLine: function (seriesIndex) {
      var serie = this.series[seriesIndex];

      if (!serie.splitLine.show) {
        return;
      }

      var params = this._paramsMap[seriesIndex];
      var splitNumber = serie.splitNumber;
      var min = serie.min;
      var total = serie.max - min;
      var splitLine = serie.splitLine;
      var length = this.parsePercent(splitLine.length, params.radius[1]);
      var lineStyle = splitLine.lineStyle;
      var color = lineStyle.color;
      var center = params.center;
      var startAngle = params.startAngle * Math.PI / 180;
      var totalAngle = params.totalAngle * Math.PI / 180;
      var r = params.radius[1];
      var r0 = r - length;
      var angle;
      var sinAngle;
      var cosAngle;

      for (var i = 0; i <= splitNumber; i++) {
        angle = startAngle - totalAngle / splitNumber * i;
        sinAngle = Math.sin(angle);
        cosAngle = Math.cos(angle);
        this.shapeList.push(new LineShape({
          zlevel: serie.zlevel,
          z: serie.z + 1,
          hoverable: false,
          style: {
            xStart: center[0] + cosAngle * r,
            yStart: center[1] - sinAngle * r,
            xEnd: center[0] + cosAngle * r0,
            yEnd: center[1] - sinAngle * r0,
            strokeColor: color === 'auto' ? this._getColor(seriesIndex, min + total / splitNumber * i) : color,
            lineType: lineStyle.type,
            lineWidth: lineStyle.width,
            shadowColor: lineStyle.shadowColor,
            shadowBlur: lineStyle.shadowBlur,
            shadowOffsetX: lineStyle.shadowOffsetX,
            shadowOffsetY: lineStyle.shadowOffsetY
          }
        }));
      }
    },
    // 小标记
    _buildAxisTick: function (seriesIndex) {
      var serie = this.series[seriesIndex];

      if (!serie.axisTick.show) {
        return;
      }

      var params = this._paramsMap[seriesIndex];
      var splitNumber = serie.splitNumber;
      var min = serie.min;
      var total = serie.max - min;
      var axisTick = serie.axisTick;
      var tickSplit = axisTick.splitNumber;
      var length = this.parsePercent(axisTick.length, params.radius[1]);
      var lineStyle = axisTick.lineStyle;
      var color = lineStyle.color;
      var center = params.center;
      var startAngle = params.startAngle * Math.PI / 180;
      var totalAngle = params.totalAngle * Math.PI / 180;
      var r = params.radius[1];
      var r0 = r - length;
      var angle;
      var sinAngle;
      var cosAngle;

      for (var i = 0, l = splitNumber * tickSplit; i <= l; i++) {
        if (i % tickSplit === 0) {
          // 同splitLine
          continue;
        }

        angle = startAngle - totalAngle / l * i;
        sinAngle = Math.sin(angle);
        cosAngle = Math.cos(angle);
        this.shapeList.push(new LineShape({
          zlevel: serie.zlevel,
          z: serie.z + 1,
          hoverable: false,
          style: {
            xStart: center[0] + cosAngle * r,
            yStart: center[1] - sinAngle * r,
            xEnd: center[0] + cosAngle * r0,
            yEnd: center[1] - sinAngle * r0,
            strokeColor: color === 'auto' ? this._getColor(seriesIndex, min + total / l * i) : color,
            lineType: lineStyle.type,
            lineWidth: lineStyle.width,
            shadowColor: lineStyle.shadowColor,
            shadowBlur: lineStyle.shadowBlur,
            shadowOffsetX: lineStyle.shadowOffsetX,
            shadowOffsetY: lineStyle.shadowOffsetY
          }
        }));
      }
    },
    // 坐标轴文本
    _buildAxisLabel: function (seriesIndex) {
      var serie = this.series[seriesIndex];

      if (!serie.axisLabel.show) {
        return;
      }

      var splitNumber = serie.splitNumber;
      var min = serie.min;
      var total = serie.max - min;
      var textStyle = serie.axisLabel.textStyle;
      var textFont = this.getFont(textStyle);
      var color = textStyle.color;
      var params = this._paramsMap[seriesIndex];
      var center = params.center;
      var startAngle = params.startAngle;
      var totalAngle = params.totalAngle;
      var r0 = params.radius[1] - this.parsePercent(serie.splitLine.length, params.radius[1]) - 5;
      var angle;
      var sinAngle;
      var cosAngle;
      var value;

      for (var i = 0; i <= splitNumber; i++) {
        value = accMath.accAdd(min, accMath.accMul(accMath.accDiv(total, splitNumber), i));
        angle = startAngle - totalAngle / splitNumber * i;
        sinAngle = Math.sin(angle * Math.PI / 180);
        cosAngle = Math.cos(angle * Math.PI / 180);
        angle = (angle + 360) % 360;
        this.shapeList.push(new TextShape({
          zlevel: serie.zlevel,
          z: serie.z + 1,
          hoverable: false,
          style: {
            x: center[0] + cosAngle * r0,
            y: center[1] - sinAngle * r0,
            color: color === 'auto' ? this._getColor(seriesIndex, value) : color,
            text: this._getLabelText(serie.axisLabel.formatter, value),
            textAlign: angle >= 110 && angle <= 250 ? 'left' : angle <= 70 || angle >= 290 ? 'right' : 'center',
            textBaseline: angle >= 10 && angle <= 170 ? 'top' : angle >= 190 && angle <= 350 ? 'bottom' : 'middle',
            textFont: textFont,
            shadowColor: textStyle.shadowColor,
            shadowBlur: textStyle.shadowBlur,
            shadowOffsetX: textStyle.shadowOffsetX,
            shadowOffsetY: textStyle.shadowOffsetY
          }
        }));
      }
    },
    _buildPointer: function (seriesIndex) {
      var serie = this.series[seriesIndex];

      if (!serie.pointer.show) {
        return;
      }

      var total = serie.max - serie.min;
      var pointer = serie.pointer;
      var params = this._paramsMap[seriesIndex];
      var length = this.parsePercent(pointer.length, params.radius[1]);
      var width = this.parsePercent(pointer.width, params.radius[1]);
      var center = params.center;

      var value = this._getValue(seriesIndex);

      value = value < serie.max ? value : serie.max;
      var angle = (params.startAngle - params.totalAngle / total * (value - serie.min)) * Math.PI / 180;
      var color = pointer.color === 'auto' ? this._getColor(seriesIndex, value) : pointer.color;
      var pointShape = new GaugePointerShape({
        zlevel: serie.zlevel,
        z: serie.z + 1,
        clickable: this.query(serie, 'clickable'),
        style: {
          x: center[0],
          y: center[1],
          r: length,
          startAngle: params.startAngle * Math.PI / 180,
          angle: angle,
          color: color,
          width: width,
          shadowColor: pointer.shadowColor,
          shadowBlur: pointer.shadowBlur,
          shadowOffsetX: pointer.shadowOffsetX,
          shadowOffsetY: pointer.shadowOffsetY
        },
        highlightStyle: {
          brushType: 'fill',
          width: width > 2 ? 2 : width / 2,
          color: '#fff'
        }
      });
      ecData.pack(pointShape, this.series[seriesIndex], seriesIndex, this.series[seriesIndex].data[0], 0, this.series[seriesIndex].data[0].name, value);
      this.shapeList.push(pointShape);
      this.shapeList.push(new CircleShape({
        zlevel: serie.zlevel,
        z: serie.z + 2,
        hoverable: false,
        style: {
          x: center[0],
          y: center[1],
          r: pointer.width / 2.5,
          color: '#fff'
        }
      }));
    },
    _buildTitle: function (seriesIndex) {
      var serie = this.series[seriesIndex];

      if (!serie.title.show) {
        return;
      }

      var data = serie.data[0];
      var name = data.name != null ? data.name : '';

      if (name !== '') {
        // 不要帮我代码规范
        var title = serie.title;
        var offsetCenter = title.offsetCenter;
        var textStyle = title.textStyle;
        var textColor = textStyle.color;
        var params = this._paramsMap[seriesIndex];
        var x = params.center[0] + this.parsePercent(offsetCenter[0], params.radius[1]);
        var y = params.center[1] + this.parsePercent(offsetCenter[1], params.radius[1]);
        this.shapeList.push(new TextShape({
          zlevel: serie.zlevel,
          z: serie.z + (Math.abs(x - params.center[0]) + Math.abs(y - params.center[1]) < textStyle.fontSize * 2 ? 2 : 1),
          hoverable: false,
          style: {
            x: x,
            y: y,
            color: textColor === 'auto' ? this._getColor(seriesIndex) : textColor,
            text: name,
            textAlign: 'center',
            textFont: this.getFont(textStyle),
            shadowColor: textStyle.shadowColor,
            shadowBlur: textStyle.shadowBlur,
            shadowOffsetX: textStyle.shadowOffsetX,
            shadowOffsetY: textStyle.shadowOffsetY
          }
        }));
      }
    },
    _buildDetail: function (seriesIndex) {
      var serie = this.series[seriesIndex];

      if (!serie.detail.show) {
        return;
      }

      var detail = serie.detail;
      var offsetCenter = detail.offsetCenter;
      var color = detail.backgroundColor;
      var textStyle = detail.textStyle;
      var textColor = textStyle.color;
      var params = this._paramsMap[seriesIndex];

      var value = this._getValue(seriesIndex);

      var x = params.center[0] - detail.width / 2 + this.parsePercent(offsetCenter[0], params.radius[1]);
      var y = params.center[1] + this.parsePercent(offsetCenter[1], params.radius[1]);
      this.shapeList.push(new RectangleShape({
        zlevel: serie.zlevel,
        z: serie.z + (Math.abs(x + detail.width / 2 - params.center[0]) + Math.abs(y + detail.height / 2 - params.center[1]) < textStyle.fontSize ? 2 : 1),
        hoverable: false,
        style: {
          x: x,
          y: y,
          width: detail.width,
          height: detail.height,
          brushType: 'both',
          color: color === 'auto' ? this._getColor(seriesIndex, value) : color,
          lineWidth: detail.borderWidth,
          strokeColor: detail.borderColor,
          shadowColor: detail.shadowColor,
          shadowBlur: detail.shadowBlur,
          shadowOffsetX: detail.shadowOffsetX,
          shadowOffsetY: detail.shadowOffsetY,
          text: this._getLabelText(detail.formatter, value),
          textFont: this.getFont(textStyle),
          textPosition: 'inside',
          textColor: textColor === 'auto' ? this._getColor(seriesIndex, value) : textColor
        }
      }));
    },
    _getValue: function (seriesIndex) {
      return this.getDataFromOption(this.series[seriesIndex].data[0]);
    },

    /**
     * 颜色索引 
     */
    _colorMap: function (seriesIndex) {
      var serie = this.series[seriesIndex];
      var min = serie.min;
      var total = serie.max - min;
      var color = serie.axisLine.lineStyle.color;

      if (!(color instanceof Array)) {
        color = [[1, color]];
      }

      var colorArray = [];

      for (var i = 0, l = color.length; i < l; i++) {
        colorArray.push([color[i][0] * total + min, color[i][1]]);
      }

      this._paramsMap[seriesIndex].colorArray = colorArray;
    },

    /**
     * 自动颜色 
     */
    _getColor: function (seriesIndex, value) {
      if (value == null) {
        value = this._getValue(seriesIndex);
      }

      var colorArray = this._paramsMap[seriesIndex].colorArray;

      for (var i = 0, l = colorArray.length; i < l; i++) {
        if (colorArray[i][0] >= value) {
          return colorArray[i][1];
        }
      }

      return colorArray[colorArray.length - 1][1];
    },

    /**
     * 构建扇形
     */
    _getSector: function (center, r0, r, startAngle, endAngle, color, lineStyle, zlevel, z) {
      return new SectorShape({
        zlevel: zlevel,
        z: z,
        hoverable: false,
        style: {
          x: center[0],
          // 圆心横坐标
          y: center[1],
          // 圆心纵坐标
          r0: r0,
          // 圆环内半径
          r: r,
          // 圆环外半径
          startAngle: startAngle,
          endAngle: endAngle,
          brushType: 'fill',
          color: color,
          shadowColor: lineStyle.shadowColor,
          shadowBlur: lineStyle.shadowBlur,
          shadowOffsetX: lineStyle.shadowOffsetX,
          shadowOffsetY: lineStyle.shadowOffsetY
        }
      });
    },

    /**
     * 根据lable.format计算label text
     */
    _getLabelText: function (formatter, value) {
      if (formatter) {
        if (typeof formatter === 'function') {
          return formatter.call(this.myChart, value);
        } else if (typeof formatter === 'string') {
          return formatter.replace('{value}', value);
        }
      }

      return value;
    },

    /**
     * 刷新
     */
    refresh: function (newOption) {
      if (newOption) {
        this.option = newOption;
        this.series = newOption.series;
      }

      this.backupShapeList();

      this._buildShape();
    }
  };
  zrUtil.inherits(Gauge, ChartBase); // 图表注册

  require('../chart').define('gauge', Gauge);

  return Gauge;
}(require);