/**
 * echarts图表类：矩形树图
 *
 * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。
 * @author Loutongbing (娄同兵, loutongbing@126.com)
 */
module.exports = function (require) {
  var ChartBase = require('./base'); // 图形依赖


  var toolArea = require('zrender/tool/area'); // 图形依赖


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

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

  var LineShape = require('zrender/shape/Line'); // 布局依赖


  var TreeMapLayout = require('../layout/TreeMap'); // 数据依赖


  var Tree = require('../data/Tree');

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


  ecConfig.treemap = {
    zlevel: 0,
    // 一级层叠
    z: 1,
    // 二级层叠
    calculable: false,
    clickable: true,
    center: ['50%', '50%'],
    size: ['80%', '80%'],
    root: '',
    itemStyle: {
      normal: {
        // color: 各异,
        label: {
          show: true,
          x: 5,
          y: 12,
          textStyle: {
            align: 'left',
            color: '#000',
            fontFamily: 'Arial',
            fontSize: 13,
            fontStyle: 'normal',
            fontWeight: 'normal'
          }
        },
        breadcrumb: {
          show: true,
          textStyle: {}
        },
        borderWidth: 1,
        borderColor: '#ccc',
        childBorderWidth: 1,
        childBorderColor: '#ccc'
      },
      emphasis: {}
    }
  };

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

  var zrConfig = require('zrender/config');

  var zrEvent = require('zrender/tool/event');

  var zrUtil = require('zrender/tool/util');

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


  function Treemap(ecTheme, messageCenter, zr, option, myChart) {
    // 图表基类
    ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
    this.refresh(option);
    var self = this;

    self._onclick = function (params) {
      return self.__onclick(params);
    };

    self.zr.on(zrConfig.EVENT.CLICK, self._onclick);
  }

  Treemap.prototype = {
    type: ecConfig.CHART_TYPE_TREEMAP,

    /**
     * 刷新
     */
    refresh: function (newOption) {
      this.clear();

      if (newOption) {
        this.option = newOption;
        this.series = this.option.series;
      } // Map storing all trees of series


      this._treesMap = {};
      var series = this.series;
      var legend = this.component.legend;

      for (var i = 0; i < series.length; i++) {
        if (series[i].type === ecConfig.CHART_TYPE_TREEMAP) {
          series[i] = this.reformOption(series[i]);
          var seriesName = series[i].name || '';
          this.selectedMap[seriesName] = legend ? legend.isSelected(seriesName) : true;

          if (!this.selectedMap[seriesName]) {
            continue;
          }

          this._buildSeries(series[i], i);
        }
      }
    },
    _buildSeries: function (series, seriesIndex) {
      var tree = Tree.fromOptionData(series.name, series.data);
      this._treesMap[seriesIndex] = tree;
      var treeRoot = series.root && tree.getNodeById(series.root) || tree.root;

      this._buildTreemap(treeRoot, seriesIndex);
    },

    /**
     * 构建单个
     *
     * @param {Object} data 数据
     */
    _buildTreemap: function (treeRoot, seriesIndex) {
      // 清除之前的 shapes
      var shapeList = this.shapeList;

      for (var i = 0; i < shapeList.length;) {
        var shape = shapeList[i];

        if (ecData.get(shape, 'seriesIndex') === seriesIndex) {
          this.zr.delShape(shapeList[i]);
          shapeList.splice(i, 1);
        } else {
          i++;
        }
      }

      var currentShapeLen = shapeList.length;
      var series = this.series[seriesIndex];
      var itemStyle = series.itemStyle;
      var treemapWidth = this.parsePercent(series.size[0], this.zr.getWidth()) || 400;
      var treemapHeight = this.parsePercent(series.size[1], this.zr.getHeight()) || 500;
      var center = this.parseCenter(this.zr, series.center);
      var treemapX = center[0] - treemapWidth * 0.5;
      var treemapY = center[1] - treemapHeight * 0.5;
      var treemapArea = treemapWidth * treemapHeight; // 计算总面积
      // 遍历数组，通过value与area0计算实际面积area

      var sum = 0;
      var areaArr = [];
      var children = treeRoot.children;

      for (var i = 0; i < children.length; i++) {
        sum += children[i].data.value;
      }

      for (var j = 0; j < children.length; j++) {
        areaArr.push(children[j].data.value * treemapArea / sum);
      }

      var treeMapLayout = new TreeMapLayout({
        x: treemapX,
        y: treemapY,
        width: treemapWidth,
        height: treemapHeight
      });
      var locationArr = treeMapLayout.run(areaArr);

      for (var k = 0; k < locationArr.length; k++) {
        var dataItem = children[k].data;
        var rect = locationArr[k];
        var queryTarget = [dataItem.itemStyle, itemStyle];
        var itemStyleMerged = this.deepMerge(queryTarget);

        if (!itemStyleMerged.normal.color) {
          itemStyleMerged.normal.color = this.zr.getColor(k);
        }

        if (!itemStyleMerged.emphasis.color) {
          itemStyleMerged.emphasis.color = itemStyleMerged.normal.color;
        }

        this._buildItem(dataItem, itemStyleMerged, rect, seriesIndex, k); // 绘制二级节点


        if (dataItem.children) {
          this._buildChildrenTreemap(dataItem.children, itemStyleMerged, rect, seriesIndex);
        }
      }

      if (this.query(series, 'itemStyle.normal.breadcrumb.show')) {
        this._buildBreadcrumb(treeRoot, seriesIndex, treemapX, treemapY + treemapHeight);
      }

      for (var i = currentShapeLen; i < shapeList.length; i++) {
        this.zr.addShape(shapeList[i]);
      }
    },

    /**
     * 构建单个item
     */
    _buildItem: function (dataItem, itemStyle, rect, seriesIndex, dataIndex) {
      var series = this.series;
      var rectangle = this.getRectangle(dataItem, itemStyle, rect); // todo

      ecData.pack(rectangle, series[seriesIndex], seriesIndex, dataItem, dataIndex, dataItem.name);
      this.shapeList.push(rectangle);
    },

    /**
     * 构建矩形
     * @param {Object} data 数据
     * @param {Object} itemStyle 合并后的样式
     * @param {number} x 矩形横坐标
     * @param {number} y 矩形纵坐标
     * @param {number} width 矩形宽
     * @param {number} height 矩形高
     * @return {Object} 返回一个矩形
     */
    getRectangle: function (dataItem, itemStyle, rect) {
      var emphasis = itemStyle.emphasis;
      var normal = itemStyle.normal;
      var textShape = this.getLabel(itemStyle, rect, dataItem.name, dataItem.value);
      var hoverable = this.option.hoverable;
      var rectangleShape = {
        zlevel: this.getZlevelBase(),
        z: this.getZBase(),
        hoverable: hoverable,
        clickable: true,
        style: zrUtil.merge({
          x: rect.x,
          y: rect.y,
          width: rect.width,
          height: rect.height,
          brushType: 'both',
          color: normal.color,
          lineWidth: normal.borderWidth,
          strokeColor: normal.borderColor
        }, textShape.style, true),
        highlightStyle: zrUtil.merge({
          color: emphasis.color,
          lineWidth: emphasis.borderWidth,
          strokeColor: emphasis.borderColor
        }, textShape.highlightStyle, true)
      };
      return new RectangleShape(rectangleShape);
    },

    /**
     * 获取label样式
     * @param {Object} itemStyle 合并后的样式
     * @param {Object} rect 矩形信息
     * @param {string} name 数据名称
     * @param {number} value 数据值
     * @return {Object} 返回label的样式
     */
    getLabel: function (itemStyle, rect, name, value) {
      var normalTextStyle = itemStyle.normal.label.textStyle;
      var queryTarget = [itemStyle.emphasis.label.textStyle, normalTextStyle];
      var emphasisTextStyle = this.deepMerge(queryTarget);
      var formatter = itemStyle.normal.label.formatter;
      var text = this.getLabelText(name, value, formatter);
      var textFont = this.getFont(normalTextStyle);
      var textWidth = toolArea.getTextWidth(text, textFont);
      var textHeight = toolArea.getTextHeight(text, textFont);
      var emphasisFormatter = this.deepQuery([itemStyle.emphasis, itemStyle.normal], 'label.formatter');
      var emphasisText = this.getLabelText(name, value, emphasisFormatter);
      var emphasisTextFont = this.getFont(emphasisTextStyle);
      var emphasisTextWidth = toolArea.getTextWidth(text, emphasisTextFont);
      var emphasisTextHeight = toolArea.getTextHeight(text, emphasisTextFont);

      if (!itemStyle.normal.label.show) {
        text = '';
      } else if (itemStyle.normal.label.x + textWidth > rect.width || itemStyle.normal.label.y + textHeight > rect.height) {
        text = '';
      }

      if (!itemStyle.emphasis.label.show) {
        emphasisText = '';
      } else if (emphasisTextStyle.x + emphasisTextWidth > rect.width || emphasisTextStyle.y + emphasisTextHeight > rect.height) {
        emphasisText = '';
      } // 用label方法写title


      var textShape = {
        style: {
          textX: rect.x + itemStyle.normal.label.x,
          textY: rect.y + itemStyle.normal.label.y,
          text: text,
          textPosition: 'specific',
          textColor: normalTextStyle.color,
          textFont: textFont
        },
        highlightStyle: {
          textX: rect.x + itemStyle.emphasis.label.x,
          textY: rect.y + itemStyle.emphasis.label.y,
          text: emphasisText,
          textColor: emphasisTextStyle.color,
          textPosition: 'specific'
        }
      };
      return textShape;
    },

    /**
     * 支持formatter
     * @param {string} name 数据名称
     * @param {number} value 数据值
     * @param {string|Object} formatter 构造器
     * @return {Object} 返回label的样式
     */
    getLabelText: function (name, value, formatter) {
      if (formatter) {
        if (typeof formatter === 'function') {
          return formatter.call(this.myChart, name, value);
        } else if (typeof formatter === 'string') {
          formatter = formatter.replace('{b}', '{b0}').replace('{c}', '{c0}');
          formatter = formatter.replace('{b0}', name).replace('{c0}', value);
          return formatter;
        }
      } else {
        return name;
      }
    },

    /*
     * 构建子级矩形图，这里用线表示不再画矩形
     *
     * @param {Object} data 数据
     * @param {Object} rect
     * @return
    */
    _buildChildrenTreemap: function (data, itemStyle, rect, seriesIndex) {
      var treemapArea = rect.width * rect.height; // 计算总面积
      // 遍历数组，通过value与area0计算实际面积area

      var sum = 0;
      var areaArr = [];

      for (var i = 0; i < data.length; i++) {
        sum += data[i].value;
      }

      for (var j = 0; j < data.length; j++) {
        areaArr.push(data[j].value * treemapArea / sum);
      }

      var treeMapLayout = new TreeMapLayout({
        x: rect.x,
        y: rect.y,
        width: rect.width,
        height: rect.height
      });
      var locationArr = treeMapLayout.run(areaArr);
      var lineWidth = itemStyle.normal.childBorderWidth;
      var lineColor = itemStyle.normal.childBorderColor;

      for (var k = 0; k < locationArr.length; k++) {
        var item = locationArr[k];
        var lines = []; // 容器边框不能重复画
        // 上边

        if (rect.y.toFixed(2) !== item.y.toFixed(2)) {
          lines.push(this._getLine(item.x, item.y, item.x + item.width, item.y, lineWidth, lineColor));
        } // 左边


        if (rect.x.toFixed(2) !== item.x.toFixed(2)) {
          lines.push(this._getLine(item.x, item.y, item.x, item.y + item.height, lineWidth, lineColor));
        } // 下边


        if ((rect.y + rect.height).toFixed(2) !== (item.y + item.height).toFixed(2)) {
          lines.push(this._getLine(item.x, item.y + item.height, item.x + item.width, item.y + item.height, lineWidth, lineColor));
        } // 右边


        if ((rect.x + rect.width).toFixed(2) !== (item.x + item.width).toFixed(2)) {
          lines.push(this._getLine(item.x + item.width, item.y, item.x + item.width, item.y + item.height, lineWidth, lineColor));
        }

        for (var l = 0; l < lines.length; l++) {
          ecData.set(lines[l], 'seriesIndex', seriesIndex);
          this.shapeList.push(lines[l]);
        }
      }
    },

    /*
     * 构建线段
     * @param {number} xStart 开始坐标
     * @param {number} yStart 开始坐标
     * @param {number} xEnd 结束坐标
     * @param {number} yEnd 结束坐标
     * @param {number} lineWidth 线宽
     * @param {number} lineColor 颜色
     * @return {Object} 返回一个线段
     */
    _getLine: function (xStart, yStart, xEnd, yEnd, lineWidth, lineColor) {
      var lineShape = {
        zlevel: this.getZlevelBase(),
        z: this.getZBase(),
        hoverable: false,
        style: {
          xStart: xStart,
          yStart: yStart,
          xEnd: xEnd,
          yEnd: yEnd,
          lineWidth: lineWidth,
          strokeColor: lineColor
        }
      };
      return new LineShape(lineShape);
    },
    _buildBreadcrumb: function (treeRoot, seriesIndex, x, y) {
      var stack = [];
      var current = treeRoot;

      while (current) {
        stack.unshift(current.data.name);
        current = current.parent;
      }

      var series = this.series[seriesIndex];
      var textStyle = this.query(series, 'itemStyle.normal.breadcrumb.textStyle') || {};
      var textEmphasisStyle = this.query(series, 'itemStyle.emphasis.breadcrumb.textStyle') || {};
      var commonStyle = {
        y: y + 10,
        textBaseline: 'top',
        textAlign: 'left',
        color: textStyle.color,
        textFont: this.getFont(textStyle)
      };
      var commonHighlightStyle = {
        brushType: 'fill',
        color: textEmphasisStyle.color || zrColor.lift(textStyle.color, -0.3),
        textFont: this.getFont(textEmphasisStyle)
      };

      for (var i = 0; i < stack.length; i++) {
        var textShape = new TextShape({
          zlevel: this.getZlevelBase(),
          z: this.getZBase(),
          style: zrUtil.merge({
            x: x,
            text: stack[i] + (stack.length - 1 - i ? ' > ' : '')
          }, commonStyle),
          clickable: true,
          highlightStyle: commonHighlightStyle
        });
        ecData.set(textShape, 'seriesIndex', seriesIndex);
        ecData.set(textShape, 'name', stack[i]);
        x += textShape.getRect(textShape.style).width;
        this.shapeList.push(textShape);
      }
    },
    __onclick: function (params) {
      var target = params.target;

      if (target) {
        var seriesIndex = ecData.get(target, 'seriesIndex');
        var name = ecData.get(target, 'name');
        var tree = this._treesMap[seriesIndex];
        var root = tree.getNodeById(name);

        if (root && root.children.length) {
          this._buildTreemap(root, seriesIndex);
        }
      }
    }
  };
  zrUtil.inherits(Treemap, ChartBase); // 图表注册

  require('../chart').define('treemap', Treemap);

  return Treemap;
}(require);