var _require = require('../../renderer'),
    Group = _require.Group;

var _require2 = require('@antv/component/lib'),
    Label = _require2.Label; // const visualCenter = require('@antv/component/lib/label/utils/visual-center');


var Global = require('../../global');

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

var IGNORE_ARR = ['line', 'point', 'path'];
var ORIGIN = '_origin';

function avg(arr) {
  var sum = 0;
  Util.each(arr, function (value) {
    sum += value;
  });
  return sum / arr.length;
} // 计算多边形重心: https://en.wikipedia.org/wiki/Centroid#Of_a_polygon


function getCentroid(xs, ys) {
  if (Util.isNumber(xs) && Util.isNumber(ys)) {
    return [xs, ys];
  }

  var i = -1,
      x = 0,
      y = 0;
  var former,
      current = xs.length - 1;
  var diff,
      k = 0;

  while (++i < xs.length) {
    former = current;
    current = i;
    k += diff = xs[former] * ys[current] - xs[current] * ys[former];
    x += (xs[former] + xs[current]) * diff;
    y += (ys[former] + ys[current]) * diff;
  }

  k *= 3;
  return [x / k, y / k];
}

var GeomLabels = function GeomLabels(cfg) {
  GeomLabels.superclass.constructor.call(this, cfg);
};

Util.extend(GeomLabels, Group);
Util.augment(GeomLabels, {
  getDefaultCfg: function getDefaultCfg() {
    return {
      label: Global.label,

      /**
       * 用户传入的文本配置信息
       * @type {Object}
       */
      labelCfg: null,

      /**
       * 所在的坐标系
       * @type {Object}
       */
      coord: null,

      /**
       * 图表的类型
       * @type {String}
       */
      geomType: null,
      zIndex: 6
    };
  },
  _renderUI: function _renderUI() {
    GeomLabels.superclass._renderUI.call(this);

    this.initLabelsCfg();
    var labelsGroup = this.addGroup();
    var lineGroup = this.addGroup({
      elCls: 'x-line-group'
    });
    var labelRenderer = this.get('labelRenderer');
    this.set('labelsGroup', labelsGroup);
    this.set('lineGroup', lineGroup);
    this.get('labelRenderer').set('group', labelsGroup);
    labelRenderer.set('group', labelsGroup);
    labelRenderer.set('lineGroup', lineGroup);
  },
  // 初始化labels的配置项
  initLabelsCfg: function initLabelsCfg() {
    var self = this;
    var labelRenderer = new Label();
    var labels = self.getDefaultLabelCfg();
    var labelCfg = self.get('labelCfg'); // Util.merge(labels, labelCfg.cfg);

    Util.deepMix(labels, labelCfg.globalCfg || labelCfg.cfg);
    labelRenderer.set('config', false);

    if (labels.labelLine) {
      labelRenderer.set('labelLine', labels.labelLine);
    }

    labelRenderer.set('coord', self.get('coord'));
    this.set('labelRenderer', labelRenderer);
    self.set('label', labels);
  },

  /**
   * @protected
   * 默认的文本样式
   * @return {Object} default label config
   */
  getDefaultLabelCfg: function getDefaultLabelCfg() {
    var self = this;
    var labelCfg = self.get('labelCfg').cfg || self.get('labelCfg').globalCfg;
    var geomType = self.get('geomType');
    var viewTheme = self.get('viewTheme') || Global;

    if (geomType === 'polygon' || labelCfg && labelCfg.offset < 0 && Util.indexOf(IGNORE_ARR, geomType) === -1) {
      return Util.deepMix({}, self.get('label'), viewTheme.innerLabels, labelCfg);
    }

    return Util.deepMix({}, self.get('label'), viewTheme.label, labelCfg);
  },

  /**
   * @protected
   * 获取labels
   * @param {Array} points points
   * @param {Array} shapes shapes
   * @return {Array} label items
   */
  getLabelsItems: function getLabelsItems(points, shapes) {
    var self = this;
    var items = [];
    var geom = self.get('geom');
    var coord = self.get('coord');

    self._getLabelCfgs(points, shapes);

    var labelCfg = self.get('labelItemCfgs'); // 获取label相关的x，y的值，获取具体的x,y,防止存在数组

    Util.each(points, function (point, i) {
      var origin = point[ORIGIN];
      var label = labelCfg[i];

      if (!label) {
        items.push(null);
        return;
      }

      if (!Util.isArray(label.text)) {
        label.text = [label.text];
      }

      var total = label.text.length;
      Util.each(label.text, function (sub, subIndex) {
        if (Util.isNil(sub) || sub === '') {
          items.push(null);
          return;
        }

        var obj = self.getLabelPoint(label, point, subIndex);
        obj = Util.mix({}, label, obj);

        if (!obj.textAlign) {
          obj.textAlign = self.getLabelAlign(obj, subIndex, total);
        }

        if (geom) {
          obj._id = geom._getShapeId(origin) + '-glabel-' + subIndex + '-' + obj.text;
        }

        obj.coord = coord;
        items.push(obj);
      });
    });
    return items;
  },

  /* /!*
   * @protected
   * 如果发生冲突则会调整文本的位置
   * @param {Array} items 文本的集合
   * @param {Array} shapes 关联形状
   * @return {Array} adjusted items
   *!/
  adjustItems(items, shapes) {
    // 多边形shape的label位于其可视中心
    if (this.get('geomType') === 'polygon') {
      let index,
        shape,
        path,
        center,
        points;
      Util.each(items, (item, i) => {
        if (!item) return;
        shape = shapes[ i ];
        path = shape.attr('path');
        points = [[]];
        index = 0;
        path.forEach((segment, i) => {
          if (segment[ 0 ] === 'z' || segment[ 0 ] === 'Z' && i !== path.length - 1) {
            points.push([]);
            index += 1;
          }
          if (segment.length === 3) {
            points[ index ].push([ segment[ 1 ], segment[ 2 ] ]);
          }
        });
        center = visualCenter(points);
        item.x = center.x;
        item.y = center.y;
      });
    }
    return items;
  }
  */
  adjustItems: function adjustItems(items) {
    Util.each(items, function (item) {
      if (!item) {
        return;
      }

      if (item.offsetX) {
        item.x += item.offsetX;
      }

      if (item.offsetY) {
        item.y += item.offsetY;
      }
    });
    return items;
  },

  /**
   * drawing lines to labels
   * @param  {Array} items labels
   * @param  {Object} labelLine configuration for label lines
   */
  drawLines: function drawLines(items) {
    var self = this;
    Util.each(items, function (point) {
      if (!point) {
        return;
      }

      if (point.offset > 0) {
        self.lineToLabel(point);
      }
    });
  },
  // 定义连接线
  lineToLabel: function lineToLabel() {},

  /**
   * @protected
   * 获取文本的位置信息
   * @param {Array} labelCfg labels
   * @param {Object} point point
   * @param {Number} index index
   * @return {Object} point
   */
  getLabelPoint: function getLabelPoint(labelCfg, point, index) {
    var self = this;
    var coord = self.get('coord');
    var total = labelCfg.text.length;

    function getDimValue(value, idx) {
      if (Util.isArray(value)) {
        if (labelCfg.text.length === 1) {
          // 如果仅一个label,多个y,取最后一个y
          if (value.length <= 2) {
            value = value[value.length - 1]; // value = value[0];
          } else {
            value = avg(value);
          }
        } else {
          value = value[idx];
        }
      }

      return value;
    }

    var label = {
      text: labelCfg.text[index]
    }; // 多边形场景,多用于地图

    if (point && this.get('geomType') === 'polygon') {
      var centroid = getCentroid(point.x, point.y); // 多边形的场景也有 x 和 y 只是数字的情况，譬如当 x 和 y 都是分类字段的时候 @see #1184

      label.x = centroid[0];
      label.y = centroid[1];
    } else {
      label.x = getDimValue(point.x, index);
      label.y = getDimValue(point.y, index);
    } // get nearest point of the shape as the label line start point


    if (point && point.nextPoints && (point.shape === 'funnel' || point.shape === 'pyramid')) {
      var maxX = -Infinity;
      point.nextPoints.forEach(function (p) {
        p = coord.convert(p);

        if (p.x > maxX) {
          maxX = p.x;
        }
      });
      label.x = (label.x + maxX) / 2;
    } // sharp edge of the pyramid


    if (point.shape === 'pyramid' && !point.nextPoints && point.points) {
      point.points.forEach(function (p) {
        p = coord.convert(p);

        if (Util.isArray(p.x) && !point.x.includes(p.x) || Util.isNumber(p.x) && point.x !== p.x) {
          label.x = (label.x + p.x) / 2;
        }
      });
    }

    if (labelCfg.position) {
      self.setLabelPosition(label, point, index, labelCfg.position);
    }

    var offsetPoint = self.getLabelOffset(labelCfg, index, total);

    if (labelCfg.offsetX) {
      offsetPoint.x += labelCfg.offsetX;
    }

    if (labelCfg.offsetY) {
      offsetPoint.y += labelCfg.offsetY;
    }

    self.transLabelPoint(label);
    label.start = {
      x: label.x,
      y: label.y
    };
    label.x += offsetPoint.x;
    label.y += offsetPoint.y;
    label.color = point.color;
    return label;
  },
  setLabelPosition: function setLabelPosition() {},
  transLabelPoint: function transLabelPoint(point) {
    var self = this;
    var coord = self.get('coord');
    var tmpPoint = coord.applyMatrix(point.x, point.y, 1);
    point.x = tmpPoint[0];
    point.y = tmpPoint[1];
  },
  getOffsetVector: function getOffsetVector(point) {
    var self = this;
    var offset = point.offset || 0;
    var coord = self.get('coord');
    var vector;

    if (coord.isTransposed) {
      // 如果x,y翻转，则偏移x
      vector = coord.applyMatrix(offset, 0);
    } else {
      // 否则，偏转y
      vector = coord.applyMatrix(0, offset);
    }

    return vector;
  },
  // 获取默认的偏移量
  getDefaultOffset: function getDefaultOffset(point) {
    var self = this;
    var offset = 0;
    var coord = self.get('coord');
    var vector = self.getOffsetVector(point);

    if (coord.isTransposed) {
      // 如果x,y翻转，则偏移x
      offset = vector[0];
    } else {
      // 否则，偏转y
      offset = vector[1];
    }

    var yScale = this.get('yScale');

    if (yScale && point.point) {
      // 仅考虑 y 单值的情况，多值的情况在这里不考虑
      var yValue = point.point[yScale.field];

      if (yValue < 0) {
        offset = offset * -1; // 如果 y 值是负值，则反向
      }
    }

    return offset;
  },
  // 获取文本的偏移位置，x,y
  getLabelOffset: function getLabelOffset(point, index, total) {
    var self = this;
    var offset = self.getDefaultOffset(point);
    var coord = self.get('coord');
    var transposed = coord.isTransposed;
    var yField = transposed ? 'x' : 'y';
    var factor = transposed ? 1 : -1; // y 方向上越大，像素的坐标越小，所以transposed时将系数变成

    var offsetPoint = {
      x: 0,
      y: 0
    };

    if (index > 0 || total === 1) {
      // 判断是否小于0
      offsetPoint[yField] = offset * factor;
    } else {
      offsetPoint[yField] = offset * factor * -1;
    }

    return offsetPoint;
  },
  getLabelAlign: function getLabelAlign(point, index, total) {
    var self = this;
    var align = 'center';
    var coord = self.get('coord');

    if (coord.isTransposed) {
      var offset = self.getDefaultOffset(point); // var vector = coord.applyMatrix(offset,0);

      if (offset < 0) {
        align = 'right';
      } else if (offset === 0) {
        align = 'center';
      } else {
        align = 'left';
      }

      if (total > 1 && index === 0) {
        if (align === 'right') {
          align = 'left';
        } else if (align === 'left') {
          align = 'right';
        }
      }
    }

    return align;
  },
  _getLabelValue: function _getLabelValue(origin, scales) {
    if (!Util.isArray(scales)) {
      scales = [scales];
    }

    var text = [];
    Util.each(scales, function (scale) {
      var value = origin[scale.field];

      if (Util.isArray(value)) {
        var tmp = [];
        Util.each(value, function (subVal) {
          tmp.push(scale.getText(subVal));
        });
        value = tmp;
      } else {
        value = scale.getText(value);
      }

      if (Util.isNil(value) || value === '') {
        text.push(null);
      }

      text.push(value);
    });
    return text;
  },
  // 获取每个label的配置
  _getLabelCfgs: function _getLabelCfgs(points) {
    var self = this;
    var labelCfg = this.get('labelCfg');
    var scales = labelCfg.scales;
    var defaultCfg = this.get('label');
    var viewTheme = self.get('viewTheme') || Global;
    var cfgs = [];

    if (labelCfg.globalCfg && labelCfg.globalCfg.type) {
      self.set('type', labelCfg.globalCfg.type);
    }

    Util.each(points, function (point, i) {
      var cfg = {};
      var origin = point[ORIGIN];

      var originText = self._getLabelValue(origin, scales);

      if (labelCfg.callback) {
        // callback中应使用原始数据，而不是数据字符串
        var originValues = scales.map(function (scale) {
          return origin[scale.field];
        }); // 将point信息以及index信息也返回，方便能够根据point以及index，返回不同的配置

        cfg = labelCfg.callback.apply(null, [].concat(originValues, [point, i]));
      }

      if (!cfg && cfg !== 0) {
        cfgs.push(null);
        return;
      }

      if (Util.isString(cfg) || Util.isNumber(cfg)) {
        cfg = {
          text: cfg
        };
      } else {
        cfg.text = cfg.content || originText[0];
        delete cfg.content;
      }

      cfg = Util.mix({}, defaultCfg, labelCfg.globalCfg || {}, cfg); // 兼容旧的源数据写在item.point中

      point.point = origin;
      cfg.point = origin;

      if (cfg.htmlTemplate) {
        cfg.useHtml = true;
        cfg.text = cfg.htmlTemplate.call(null, cfg.text, point, i);
        delete cfg.htmlTemplate;
      }

      if (cfg.formatter) {
        cfg.text = cfg.formatter.call(null, cfg.text, point, i);
        delete cfg.formatter;
      }

      if (cfg.label) {
        // 兼容有些直接写在labelCfg.label的配置
        var label = cfg.label;
        delete cfg.label;
        cfg = Util.mix(cfg, label);
      }

      if (cfg.textStyle) {
        // 兼容旧写法，globalCfg的offset优先级高
        delete cfg.textStyle.offset;
        var textStyle = cfg.textStyle;

        if (Util.isFunction(textStyle)) {
          cfg.textStyle = textStyle.call(null, cfg.text, point, i);
        }
      }

      if (cfg.labelLine) {
        cfg.labelLine = Util.mix({}, defaultCfg.labelLine, cfg.labelLine);
      } // 因为 defaultCfg.textStyle 有可能是函数，所以这里可能没有把主题的 label 样式合进来


      cfg.textStyle = Util.mix({}, defaultCfg.textStyle, viewTheme.label.textStyle, cfg.textStyle);
      delete cfg.items;
      cfgs.push(cfg);
    });
    this.set('labelItemCfgs', cfgs);
  },
  showLabels: function showLabels(points, shapes) {
    var self = this;
    var labelRenderer = self.get('labelRenderer');
    var items = self.getLabelsItems(points, shapes);
    shapes = [].concat(shapes);
    var type = self.get('type');
    items = self.adjustItems(items, shapes);
    self.drawLines(items);
    labelRenderer.set('items', items.filter(function (item, i) {
      if (!item) {
        shapes.splice(i, 1);
        return false;
      }

      return true;
    }));

    if (type) {
      labelRenderer.set('shapes', shapes);
      labelRenderer.set('type', type);
      labelRenderer.set('points', points);
    }

    labelRenderer.set('canvas', this.get('canvas'));
    labelRenderer.draw();
  },
  destroy: function destroy() {
    this.get('labelRenderer').destroy(); // 清理文本

    GeomLabels.superclass.destroy.call(this);
  }
}); // Util.assign(GeomLabels.prototype, Labels.LabelslabelRenderer);

module.exports = GeomLabels;