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


  var CandleShape = require('../util/shape/Candle'); // 组件依赖


  require('../component/axis');

  require('../component/grid');

  require('../component/dataZoom');

  var ecConfig = require('../config'); // K线图默认参数


  ecConfig.k = {
    zlevel: 0,
    // 一级层叠
    z: 2,
    // 二级层叠
    clickable: true,
    hoverable: true,
    legendHoverLink: false,
    xAxisIndex: 0,
    yAxisIndex: 0,
    // barWidth: null               // 默认自适应
    // barMaxWidth: null            // 默认自适应 
    itemStyle: {
      normal: {
        color: '#fff',
        // 阳线填充颜色
        color0: '#00aa11',
        // 阴线填充颜色
        lineStyle: {
          width: 1,
          color: '#ff3200',
          // 阳线边框颜色
          color0: '#00aa11' // 阴线边框颜色

        },
        label: {
          show: false // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调
          // position: 默认自适应，水平布局为'top'，垂直布局为'right'，可选为
          //           'inside'|'left'|'right'|'top'|'bottom'
          // textStyle: null      // 默认使用全局文本样式，详见TEXTSTYLE

        }
      },
      emphasis: {
        // color: 各异,
        // color0: 各异,
        label: {
          show: false // formatter: 标签文本格式器，同Tooltip.formatter，不支持异步回调
          // position: 默认自适应，水平布局为'top'，垂直布局为'right'，可选为
          //           'inside'|'left'|'right'|'top'|'bottom'
          // textStyle: null      // 默认使用全局文本样式，详见TEXTSTYLE

        }
      }
    }
  };

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

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


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

  K.prototype = {
    type: ecConfig.CHART_TYPE_K,

    /**
     * 绘制图形
     */
    _buildShape: function () {
      var series = this.series;
      this.selectedMap = {}; // 水平垂直双向series索引 ，position索引到seriesIndex

      var _position2sIndexMap = {
        top: [],
        bottom: []
      };
      var xAxis;

      for (var i = 0, l = series.length; i < l; i++) {
        if (series[i].type === ecConfig.CHART_TYPE_K) {
          series[i] = this.reformOption(series[i]);
          this.legendHoverLink = series[i].legendHoverLink || this.legendHoverLink;
          xAxis = this.component.xAxis.getAxis(series[i].xAxisIndex);

          if (xAxis.type === ecConfig.COMPONENT_TYPE_AXIS_CATEGORY) {
            _position2sIndexMap[xAxis.getPosition()].push(i);
          }
        }
      } //console.log(_position2sIndexMap)


      for (var position in _position2sIndexMap) {
        if (_position2sIndexMap[position].length > 0) {
          this._buildSinglePosition(position, _position2sIndexMap[position]);
        }
      }

      this.addShapeList();
    },

    /**
     * 构建单个方向上的K线图
     *
     * @param {number} seriesIndex 系列索引
     */
    _buildSinglePosition: function (position, seriesArray) {
      var mapData = this._mapData(seriesArray);

      var locationMap = mapData.locationMap;
      var maxDataLength = mapData.maxDataLength;

      if (maxDataLength === 0 || locationMap.length === 0) {
        return;
      }

      this._buildHorizontal(seriesArray, maxDataLength, locationMap);

      for (var i = 0, l = seriesArray.length; i < l; i++) {
        this.buildMark(seriesArray[i]);
      }
    },

    /**
     * 数据整形
     * 数组位置映射到系列索引
     */
    _mapData: function (seriesArray) {
      var series = this.series;
      var serie; // 临时映射变量

      var serieName; // 临时映射变量

      var legend = this.component.legend;
      var locationMap = []; // 需要返回的东西：数组位置映射到系列索引

      var maxDataLength = 0; // 需要返回的东西：最大数据长度
      // 计算需要显示的个数和分配位置并记在下面这个结构里

      for (var i = 0, l = seriesArray.length; i < l; i++) {
        serie = series[seriesArray[i]];
        serieName = serie.name;
        this.selectedMap[serieName] = legend ? legend.isSelected(serieName) : true;

        if (this.selectedMap[serieName]) {
          locationMap.push(seriesArray[i]);
        } // 兼职帮算一下最大长度


        maxDataLength = Math.max(maxDataLength, serie.data.length);
      }

      return {
        locationMap: locationMap,
        maxDataLength: maxDataLength
      };
    },

    /**
     * 构建类目轴为水平方向的K线图系列
     */
    _buildHorizontal: function (seriesArray, maxDataLength, locationMap) {
      var series = this.series; // 确定类目轴和数值轴，同一方向随便找一个即可

      var seriesIndex;
      var serie;
      var xAxisIndex;
      var categoryAxis;
      var yAxisIndex; // 数值轴各异

      var valueAxis; // 数值轴各异

      var pointList = {};
      var candleWidth;
      var data;
      var value;
      var barMaxWidth;

      for (var j = 0, k = locationMap.length; j < k; j++) {
        seriesIndex = locationMap[j];
        serie = series[seriesIndex];
        xAxisIndex = serie.xAxisIndex || 0;
        categoryAxis = this.component.xAxis.getAxis(xAxisIndex);
        candleWidth = serie.barWidth || Math.floor(categoryAxis.getGap() / 2);
        barMaxWidth = serie.barMaxWidth;

        if (barMaxWidth && barMaxWidth < candleWidth) {
          candleWidth = barMaxWidth;
        }

        yAxisIndex = serie.yAxisIndex || 0;
        valueAxis = this.component.yAxis.getAxis(yAxisIndex);
        pointList[seriesIndex] = [];

        for (var i = 0, l = maxDataLength; i < l; i++) {
          if (categoryAxis.getNameByIndex(i) == null) {
            // 系列数据超出类目轴长度
            break;
          }

          data = serie.data[i];
          value = this.getDataFromOption(data, '-');

          if (value === '-' || value.length != 4) {
            // 数据格式不符
            continue;
          }

          pointList[seriesIndex].push([categoryAxis.getCoordByIndex(i), // 横坐标
          candleWidth, valueAxis.getCoord(value[0]), // 纵坐标：开盘
          valueAxis.getCoord(value[1]), // 纵坐标：收盘
          valueAxis.getCoord(value[2]), // 纵坐标：最低
          valueAxis.getCoord(value[3]), // 纵坐标：最高
          i, // 数据index
          categoryAxis.getNameByIndex(i) // 类目名称
          ]);
        }
      } // console.log(pointList)


      this._buildKLine(seriesArray, pointList);
    },

    /**
     * 生成K线
     */
    _buildKLine: function (seriesArray, pointList) {
      var series = this.series; // normal:

      var nLineWidth;
      var nLineColor;
      var nLineColor0; // 阴线

      var nColor;
      var nColor0; // 阴线
      // emphasis:

      var eLineWidth;
      var eLineColor;
      var eLineColor0;
      var eColor;
      var eColor0;
      var serie;
      var queryTarget;
      var data;
      var seriesPL;
      var singlePoint;
      var candleType;
      var seriesIndex;

      for (var sIdx = 0, len = seriesArray.length; sIdx < len; sIdx++) {
        seriesIndex = seriesArray[sIdx];
        serie = series[seriesIndex];
        seriesPL = pointList[seriesIndex];

        if (this._isLarge(seriesPL)) {
          seriesPL = this._getLargePointList(seriesPL);
        }

        if (serie.type === ecConfig.CHART_TYPE_K && seriesPL != null) {
          // 多级控制
          queryTarget = serie;
          nLineWidth = this.query(queryTarget, 'itemStyle.normal.lineStyle.width');
          nLineColor = this.query(queryTarget, 'itemStyle.normal.lineStyle.color');
          nLineColor0 = this.query(queryTarget, 'itemStyle.normal.lineStyle.color0');
          nColor = this.query(queryTarget, 'itemStyle.normal.color');
          nColor0 = this.query(queryTarget, 'itemStyle.normal.color0');
          eLineWidth = this.query(queryTarget, 'itemStyle.emphasis.lineStyle.width');
          eLineColor = this.query(queryTarget, 'itemStyle.emphasis.lineStyle.color');
          eLineColor0 = this.query(queryTarget, 'itemStyle.emphasis.lineStyle.color0');
          eColor = this.query(queryTarget, 'itemStyle.emphasis.color');
          eColor0 = this.query(queryTarget, 'itemStyle.emphasis.color0');
          /*
           * pointlist=[
           *      0  x,
           *      1  width, 
           *      2  y0,
           *      3  y1,
           *      4  y2,
           *      5  y3,
           *      6  dataIndex,
           *      7  categoryName
           * ]
           */

          for (var i = 0, l = seriesPL.length; i < l; i++) {
            singlePoint = seriesPL[i];
            data = serie.data[singlePoint[6]];
            queryTarget = data;
            candleType = singlePoint[3] < singlePoint[2];
            this.shapeList.push(this._getCandle(seriesIndex, // seriesIndex
            singlePoint[6], // dataIndex
            singlePoint[7], // name
            singlePoint[0], // x
            singlePoint[1], // width
            singlePoint[2], // y开盘
            singlePoint[3], // y收盘
            singlePoint[4], // y最低
            singlePoint[5], // y最高
            // 填充颜色
            candleType ? this.query( // 阳
            queryTarget, 'itemStyle.normal.color') || nColor : this.query( // 阴
            queryTarget, 'itemStyle.normal.color0') || nColor0, // 线宽
            this.query(queryTarget, 'itemStyle.normal.lineStyle.width') || nLineWidth, // 线色
            candleType ? this.query( // 阳
            queryTarget, 'itemStyle.normal.lineStyle.color') || nLineColor : this.query( // 阴
            queryTarget, 'itemStyle.normal.lineStyle.color0') || nLineColor0, //------------高亮
            // 填充颜色
            candleType ? this.query( // 阳
            queryTarget, 'itemStyle.emphasis.color') || eColor || nColor : this.query( // 阴
            queryTarget, 'itemStyle.emphasis.color0') || eColor0 || nColor0, // 线宽
            this.query(queryTarget, 'itemStyle.emphasis.lineStyle.width') || eLineWidth || nLineWidth, // 线色
            candleType ? this.query( // 阳
            queryTarget, 'itemStyle.emphasis.lineStyle.color') || eLineColor || nLineColor : this.query( // 阴
            queryTarget, 'itemStyle.emphasis.lineStyle.color0') || eLineColor0 || nLineColor0));
          }
        }
      } // console.log(this.shapeList)

    },
    _isLarge: function (singlePL) {
      return singlePL[0][1] < 0.5;
    },

    /**
     * 大规模pointList优化 
     */
    _getLargePointList: function (singlePL) {
      var total = this.component.grid.getWidth();
      var len = singlePL.length;
      var newList = [];

      for (var i = 0; i < total; i++) {
        newList[i] = singlePL[Math.floor(len / total * i)];
      }

      return newList;
    },

    /**
     * 生成K线图上的图形
     */
    _getCandle: function (seriesIndex, dataIndex, name, x, width, y0, y1, y2, y3, nColor, nLinewidth, nLineColor, eColor, eLinewidth, eLineColor) {
      var series = this.series;
      var serie = series[seriesIndex];
      var data = serie.data[dataIndex];
      var queryTarget = [data, serie];
      var itemShape = {
        zlevel: serie.zlevel,
        z: serie.z,
        clickable: this.deepQuery(queryTarget, 'clickable'),
        hoverable: this.deepQuery(queryTarget, 'hoverable'),
        style: {
          x: x,
          y: [y0, y1, y2, y3],
          width: width,
          color: nColor,
          strokeColor: nLineColor,
          lineWidth: nLinewidth,
          brushType: 'both'
        },
        highlightStyle: {
          color: eColor,
          strokeColor: eLineColor,
          lineWidth: eLinewidth
        },
        _seriesIndex: seriesIndex
      };
      itemShape = this.addLabel(itemShape, serie, data, name);
      ecData.pack(itemShape, serie, seriesIndex, data, dataIndex, name);
      itemShape = new CandleShape(itemShape);
      return itemShape;
    },
    // 位置转换
    getMarkCoord: function (seriesIndex, mpData) {
      var serie = this.series[seriesIndex];
      var xAxis = this.component.xAxis.getAxis(serie.xAxisIndex);
      var yAxis = this.component.yAxis.getAxis(serie.yAxisIndex);
      return [typeof mpData.xAxis != 'string' && xAxis.getCoordByIndex ? xAxis.getCoordByIndex(mpData.xAxis || 0) : xAxis.getCoord(mpData.xAxis || 0), typeof mpData.yAxis != 'string' && yAxis.getCoordByIndex ? yAxis.getCoordByIndex(mpData.yAxis || 0) : yAxis.getCoord(mpData.yAxis || 0)];
    },

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

      this.backupShapeList();

      this._buildShape();
    },

    /**
     * 动画设定
     */
    addDataAnimation: function (params, done) {
      var series = this.series;
      var aniMap = {}; // seriesIndex索引参数

      for (var i = 0, l = params.length; i < l; i++) {
        aniMap[params[i][0]] = params[i];
      }

      var x;
      var dx;
      var y;
      var serie;
      var seriesIndex;
      var dataIndex;
      var aniCount = 0;

      function animationDone() {
        aniCount--;

        if (aniCount === 0) {
          done && done();
        }
      }

      for (var i = 0, l = this.shapeList.length; i < l; i++) {
        seriesIndex = this.shapeList[i]._seriesIndex;

        if (aniMap[seriesIndex] && !aniMap[seriesIndex][3]) {
          // 有数据删除才有移动的动画
          if (this.shapeList[i].type === 'candle') {
            dataIndex = ecData.get(this.shapeList[i], 'dataIndex');
            serie = series[seriesIndex];

            if (aniMap[seriesIndex][2] && dataIndex === serie.data.length - 1) {
              // 队头加入删除末尾
              this.zr.delShape(this.shapeList[i].id);
              continue;
            } else if (!aniMap[seriesIndex][2] && dataIndex === 0) {
              // 队尾加入删除头部
              this.zr.delShape(this.shapeList[i].id);
              continue;
            }

            dx = this.component.xAxis.getAxis(serie.xAxisIndex || 0).getGap();
            x = aniMap[seriesIndex][2] ? dx : -dx;
            y = 0;
            aniCount++;
            this.zr.animate(this.shapeList[i].id, '').when(this.query(this.option, 'animationDurationUpdate'), {
              position: [x, y]
            }).done(animationDone).start();
          }
        }
      } // 没有动画


      if (!aniCount) {
        done && done();
      }
    }
  };
  zrUtil.inherits(K, ChartBase); // 图表注册

  require('../chart').define('k', K);

  return K;
}(require);