function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

/**
 * @fileOverview The controller of tooltip
 * @author sima.zhang
 */
var Util = require('../../util');

var Shape = require('../../geom/shape/shape');

var _require = require('@antv/component/lib'),
    Tooltip = _require.Tooltip;

var MatrixUtil = Util.MatrixUtil;
var Vector2 = MatrixUtil.vec2;
var TYPE_SHOW_MARKERS = ['line', 'area', 'path', 'areaStack']; // 默认展示 tooltip marker 的几何图形

var TYPE_SHOW_CROSSHAIRS = ['line', 'area', 'point']; // 默认展示十字瞄准线的几何图形
// TODO FIXME this is HARD CODING

var IGNORE_TOOLTIP_ITEM_PROPERTIES = ['marker', 'showMarker'];

function _indexOfArray(items, item) {
  var rst = -1;
  Util.each(items, function (sub, index) {
    var isEqual = true;

    for (var key in item) {
      if (item.hasOwnProperty(key) && !IGNORE_TOOLTIP_ITEM_PROPERTIES.includes(key)) {
        if (!Util.isObject(item[key]) && item[key] !== sub[key]) {
          isEqual = false;
          break;
        }
      }
    }

    if (isEqual) {
      rst = index;
      return false;
    }
  });
  return rst;
} // 判断是否有样式


function _hasClass(dom, className) {
  if (!dom) {
    return false;
  }

  var cls = '';
  if (!dom.className) return false;

  if (!Util.isNil(dom.className.baseVal)) {
    cls = dom.className.baseVal;
  } else {
    cls = dom.className;
  }

  return cls.includes(className);
}

function _isParent(dom, cls) {
  var parent = dom.parentNode;
  var rst = false;

  while (parent && parent !== document.body) {
    if (_hasClass(parent, cls)) {
      rst = true;
      break;
    }

    parent = parent.parentNode;
  }

  return rst;
} // 去除重复的值, 去除不同图形相同数据，只展示一份即可


function _uniqItems(items) {
  var tmp = [];
  Util.each(items, function (item) {
    var index = _indexOfArray(tmp, item);

    if (index === -1) {
      tmp.push(item);
    } else {
      tmp[index] = item;
    }
  });
  return tmp;
}

var TooltipController = /*#__PURE__*/function () {
  function TooltipController(cfg) {
    Util.assign(this, cfg);
    this.timeStamp = 0; // tooltip 锁定不能移动

    this.locked = false;
  }

  var _proto = TooltipController.prototype;

  _proto._normalizeEvent = function _normalizeEvent(event) {
    var chart = this.chart;

    var canvas = this._getCanvas();

    var point = canvas.getPointByClient(event.clientX, event.clientY);
    var pixelRatio = canvas.get('pixelRatio');
    point.x = point.x / pixelRatio;
    point.y = point.y / pixelRatio;
    var views = chart.getViewsByPoint(point);
    point.views = views;
    return point;
  };

  _proto._getCanvas = function _getCanvas() {
    return this.chart.get('canvas');
  };

  _proto._getTriggerEvent = function _getTriggerEvent() {
    var options = this.options;
    var triggerOn = options.triggerOn;
    var eventName;

    if (!triggerOn || triggerOn === 'mousemove') {
      eventName = 'plotmove';
    } else if (triggerOn === 'click') {
      eventName = 'plotclick';
    } else if (triggerOn === 'none') {
      eventName = null;
    }

    return eventName;
  };

  _proto._getDefaultTooltipCfg = function _getDefaultTooltipCfg() {
    var self = this;
    var chart = self.chart;
    var viewTheme = self.viewTheme;
    var options = self.options;
    var defaultCfg = Util.mix({}, viewTheme.tooltip);
    var geoms = chart.getAllGeoms().filter(function (geom) {
      return geom.get('visible');
    });
    var shapes = [];
    Util.each(geoms, function (geom) {
      var type = geom.get('type');
      var adjusts = geom.get('adjusts');
      var isSymmetric = false;

      if (adjusts) {
        Util.each(adjusts, function (adjust) {
          if (adjust.type === 'symmetric' || adjust.type === 'Symmetric') {
            isSymmetric = true;
            return false;
          }
        });
      }

      if (Util.indexOf(shapes, type) === -1 && !isSymmetric) {
        shapes.push(type);
      }
    });
    var isTransposed = geoms.length && geoms[0].get('coord') ? geoms[0].get('coord').isTransposed : false;
    var crosshairsCfg;

    if (geoms.length && geoms[0].get('coord') && geoms[0].get('coord').type === 'cartesian') {
      if (shapes[0] === 'interval' && options.shared !== false) {
        // 直角坐标系下 interval 的 crosshair 为矩形背景框
        var crosshairs = Util.mix({}, viewTheme.tooltipCrosshairsRect);
        crosshairs.isTransposed = isTransposed;
        crosshairsCfg = {
          zIndex: 0,
          // 矩形背景框不可覆盖 geom
          crosshairs: crosshairs
        };
      } else if (Util.indexOf(TYPE_SHOW_CROSSHAIRS, shapes[0]) > -1) {
        var _crosshairs = Util.mix({}, viewTheme.tooltipCrosshairsLine);

        _crosshairs.isTransposed = isTransposed;
        crosshairsCfg = {
          crosshairs: _crosshairs
        };
      }
    }

    return Util.mix(defaultCfg, crosshairsCfg, {});
  };

  _proto._bindEvent = function _bindEvent() {
    var chart = this.chart;

    var triggerEvent = this._getTriggerEvent();

    if (triggerEvent) {
      chart.on(triggerEvent, Util.wrapBehavior(this, 'onMouseMove'));
      chart.on('plotleave', Util.wrapBehavior(this, 'onMouseOut'));
    }
  };

  _proto._offEvent = function _offEvent() {
    var chart = this.chart;

    var triggerEvent = this._getTriggerEvent();

    if (triggerEvent) {
      chart.off(triggerEvent, Util.getWrapBehavior(this, 'onMouseMove'));
      chart.off('plotleave', Util.getWrapBehavior(this, 'onMouseOut'));
    }
  };

  _proto._setTooltip = function _setTooltip(point, items, markersItems, target) {
    var self = this;
    var tooltip = self.tooltip;
    var prePoint = self.prePoint;

    if (!prePoint || prePoint.x !== point.x || prePoint.y !== point.y) {
      items = _uniqItems(items);
      self.prePoint = point;
      var chart = self.chart;
      var viewTheme = self.viewTheme;
      var x = Util.isArray(point.x) ? point.x[point.x.length - 1] : point.x;
      var y = Util.isArray(point.y) ? point.y[point.y.length - 1] : point.y;

      if (!tooltip.get('visible')) {
        chart.emit('tooltip:show', {
          x: x,
          y: y,
          tooltip: tooltip
        });
      }

      var first = items[0];
      var title = first.title || first.name;

      if (tooltip.isContentChange(title, items)) {
        chart.emit('tooltip:change', {
          tooltip: tooltip,
          x: x,
          y: y,
          items: items
        }); // bugfix: when set the title in the tooltip:change event does not take effect.

        title = items[0].title || items[0].name;
        tooltip.setContent(title, items);

        if (!Util.isEmpty(markersItems)) {
          if (self.options.hideMarkers === true) {
            // 不展示 tooltip marker
            tooltip.set('markerItems', markersItems); // 用于 tooltip 辅助线的定位
          } else {
            tooltip.setMarkers(markersItems, viewTheme.tooltipMarker);
          }
        } else {
          tooltip.clearMarkers(); // clearMarkers 只会将 markerItems 从 markerGroup 中移除
          // 所以我们还要将 markerItems 从 tooltip 中移除
          // 这么做是为了防止上一次设置 marker 时的 markerItems 影响此次 tooltip 辅助线的定位

          tooltip.set('markerItems', []);
        }
      }

      var canvas = this._getCanvas();

      if (target === canvas && tooltip.get('type') === 'mini') {
        // filter mini tooltip
        tooltip.hide();
      } else {
        tooltip.setPosition(x, y, target);
        tooltip.show();
      }
    }
  };

  _proto.hideTooltip = function hideTooltip() {
    var tooltip = this.tooltip;
    var chart = this.chart;

    var canvas = this._getCanvas();

    this.prePoint = null;
    tooltip.hide();
    chart.emit('tooltip:hide', {
      tooltip: tooltip
    });
    canvas.draw();
  };

  _proto.onMouseMove = function onMouseMove(ev) {
    // 锁定时不移动 tooltip
    if (Util.isEmpty(ev.views) || this.locked) {
      return;
    }

    var lastTimeStamp = this.timeStamp;
    var timeStamp = +new Date();
    var point = {
      x: ev.x,
      y: ev.y
    };

    if (timeStamp - lastTimeStamp > 16 && !this.chart.get('stopTooltip')) {
      this.showTooltip(point, ev.views, ev.shape);
      this.timeStamp = timeStamp;
    }
  };

  _proto.onMouseOut = function onMouseOut(ev) {
    var tooltip = this.tooltip; // 锁定 tooltip 时不隐藏

    if (!tooltip.get('visible') || !tooltip.get('follow') || this.locked) {
      return;
    } // 除非离开 plot 时鼠标依然在图形上，这段逻辑没有意义
    // if (ev && ev.target !== canvas) {
    //   return;
    // }


    if (ev && ev.toElement && (_hasClass(ev.toElement, 'g2-tooltip') || _isParent(ev.toElement, 'g2-tooltip'))) {
      return;
    }

    this.hideTooltip();
  };

  _proto.renderTooltip = function renderTooltip() {
    var self = this;

    if (self.tooltip) {
      // tooltip 对象已经创建
      return;
    }

    var chart = self.chart;
    var viewTheme = self.viewTheme;

    var canvas = self._getCanvas();

    var defaultCfg = self._getDefaultTooltipCfg();

    var options = self.options;
    options = Util.deepMix({
      plotRange: chart.get('plotRange'),
      capture: false,
      canvas: canvas,
      frontPlot: chart.get('frontPlot'),
      viewTheme: viewTheme.tooltip,
      backPlot: chart.get('backPlot')
    }, defaultCfg, options);

    if (options.crosshairs && options.crosshairs.type === 'rect') {
      options.zIndex = 0; // toolip 背景框不可遮盖住 geom，防止用户配置了 crosshairs
    }

    options.visible = false; // @2018-09-13 by blue.lb 如果设置shared为false不需要指定position
    // if (options.shared === false && Util.isNil(options.position)) {
    //   options.position = 'top';
    // }

    var tooltip;

    if (options.type === 'mini') {
      options.crosshairs = false; // this.options.shared = false;

      options.position = 'top';
      tooltip = new Tooltip.Mini(options);
    } else if (options.useHtml) {
      tooltip = new Tooltip.Html(options);
    } else {
      tooltip = new Tooltip.Canvas(options);
    }

    self.tooltip = tooltip;

    var triggerEvent = self._getTriggerEvent();

    var tooltipContainer = tooltip.get('container');

    if (!tooltip.get('enterable') && triggerEvent === 'plotmove') {
      // 鼠标不允许进入 tooltip 容器
      if (tooltipContainer) {
        tooltipContainer.onmousemove = function (e) {
          // 避免 tooltip 频繁闪烁
          var eventObj = self._normalizeEvent(e);

          chart.emit(triggerEvent, eventObj);
        };
      }
    } // 优化：鼠标移入 tooltipContainer 然后再移出时，需要隐藏 tooltip


    if (tooltipContainer) {
      tooltipContainer.onmouseleave = function () {
        if (!self.locked) {
          self.hideTooltip();
        }
      };
    }

    self._bindEvent();
  };

  _proto._formatMarkerOfItem = function _formatMarkerOfItem(coord, geom, item) {
    var self = this;
    var options = self.options;
    var point = item.point;

    if (point && point.x && point.y) {
      // hotfix: make sure there is no null value
      var x = Util.isArray(point.x) ? point.x[point.x.length - 1] : point.x;
      var y = Util.isArray(point.y) ? point.y[point.y.length - 1] : point.y;
      point = coord.applyMatrix(x, y, 1);
      item.x = point[0];
      item.y = point[1];
      item.showMarker = true; // bugfix
      // 由于tooltip是DOM而不是Canvas，设置渐变色时，marker无法正常显示
      // 如果，设置的颜色是渐变色并且设置了tooltip使用html方式渲染，则取渐变色的起始颜色作为marker的颜色，暂时解决这个问题

      if (item.color.substring(0, 2) === 'l(' && (!options.hasOwnProperty('useHtml') || options.useHtml)) {
        item.color = item.color.split(' ')[1].substring(2);
      }

      var itemMarker = self._getItemMarker(geom, item);

      item.marker = itemMarker;

      if (Util.indexOf(TYPE_SHOW_MARKERS, geom.get('type')) !== -1) {
        return item;
      }
    }

    return null;
  };

  _proto.lockTooltip = function lockTooltip() {
    this.locked = true;
  };

  _proto.unlockTooltip = function unlockTooltip() {
    this.locked = false;
  };

  _proto.showTooltip = function showTooltip(point, views, target) {
    var _this = this;

    var self = this;

    if (Util.isEmpty(views) || !point) {
      return;
    }

    if (!this.tooltip) {
      this.renderTooltip(); // 如果一开始 tooltip 关闭，用户重新调用的时候需要先生成 tooltip
    }

    var options = self.options;
    var markersItems = [];
    var items = [];
    Util.each(views, function (view) {
      if (!view.get('tooltipEnable')) {
        // 如果不显示tooltip，则跳过
        return true;
      }

      var geoms = view.get('geoms');
      var coord = view.get('coord');
      Util.each(geoms, function (geom) {
        var type = geom.get('type');

        if (geom.get('visible') && geom.get('tooltipCfg') !== false) {
          var dataArray = geom.get('dataArray');

          if (geom.isShareTooltip() || options.shared === false && Util.inArray(['area', 'line', 'path', 'polygon'], type)) {
            // 打补丁解决 bug: https://github.com/antvis/g2/issues/1248
            // 当 interval 对应的 color 和 x 字段相同的时候，并且包含 dodge，items 取值逻辑不一样
            // 这种情况下，每一个 x 字段分成一组
            var xScale = geom.getXScale();
            var colorAttr = geom.getAttr('color');
            var colorField = colorAttr ? colorAttr.field : undefined;

            if (type === 'interval' && xScale.field === colorField && geom.hasAdjust('dodge')) {
              // 找不到不为空的
              var points = Util.find(dataArray, function (obj) {
                return !!geom.findPoint(point, obj);
              }); // 转为 tooltip items

              Util.each(points, function (tmpPoint) {
                var subItems = geom.getTipItems(tmpPoint, options.title);
                Util.each(subItems, function (v) {
                  var markerItem = self._formatMarkerOfItem(coord, geom, v);

                  if (markerItem) {
                    markersItems.push(markerItem);
                  }
                });
                items = items.concat(subItems);
              });
            } else {
              Util.each(dataArray, function (obj) {
                var tmpPoint = geom.findPoint(point, obj);

                if (tmpPoint) {
                  var subItems = geom.getTipItems(tmpPoint, options.title);
                  Util.each(subItems, function (v) {
                    var markerItem = self._formatMarkerOfItem(coord, geom, v);

                    if (markerItem) {
                      markersItems.push(markerItem);
                    }
                  });
                  items = items.concat(subItems);
                }
              });
            }
          } else {
            var geomContainer = geom.get('shapeContainer');
            var canvas = geomContainer.get('canvas');
            var pixelRatio = canvas.get('pixelRatio');
            var shape = geomContainer.getShape(point.x * pixelRatio, point.y * pixelRatio);

            if (shape && shape.get('visible') && shape.get('origin')) {
              items = geom.getTipItems(shape.get('origin'), options.title);
            }

            Util.each(items, function (v) {
              var markerItem = _this._formatMarkerOfItem(coord, geom, v);

              if (markerItem) {
                markersItems.push(markerItem);
              }
            });
          }
        }
      });
      Util.each(items, function (item) {
        var point = item.point;
        var x = Util.isArray(point.x) ? point.x[point.x.length - 1] : point.x;
        var y = Util.isArray(point.y) ? point.y[point.y.length - 1] : point.y;
        point = coord.applyMatrix(x, y, 1);
        item.x = point[0];
        item.y = point[1];
      });
    });

    if (items.length) {
      var first = items[0]; // bugfix: multiple tooltip items with different titles

      if (!items.every(function (item) {
        return item.title === first.title;
      })) {
        var nearestItem = first;
        var nearestDistance = Infinity;
        items.forEach(function (item) {
          var distance = Vector2.distance([point.x, point.y], [item.x, item.y]);

          if (distance < nearestDistance) {
            nearestDistance = distance;
            nearestItem = item;
          }
        });
        items = items.filter(function (item) {
          return item.title === nearestItem.title;
        });
        markersItems = markersItems.filter(function (item) {
          return item.title === nearestItem.title;
        });
      }

      if (options.shared === false && items.length > 1) {
        var snapItem = items[0];
        var min = Math.abs(point.y - snapItem.y);
        Util.each(items, function (aItem) {
          if (Math.abs(point.y - aItem.y) <= min) {
            snapItem = aItem;
            min = Math.abs(point.y - aItem.y);
          }
        });

        if (snapItem && snapItem.x && snapItem.y) {
          markersItems = [snapItem];
        }

        items = [snapItem];
      } // 3.0 采用当前鼠标位置作为 tooltip 的参考点
      // if (!Util.isEmpty(markersItems)) {
      //   point = markersItems[0];
      // }


      self._setTooltip(point, items, markersItems, target);
    } else {
      self.hideTooltip();
    }
  };

  _proto.clear = function clear() {
    var tooltip = this.tooltip;
    tooltip && tooltip.destroy();
    this.tooltip = null;
    this.prePoint = null;

    this._offEvent();
  };

  _proto._getItemMarker = function _getItemMarker(geom, item) {
    var options = this.options;
    var markerOption = options.marker || this.viewTheme.tooltip.marker;

    if (Util.isFunction(markerOption)) {
      var shapeType = geom.get('shapeType') || 'point';
      var shape = geom.getDefaultValue('shape') || 'circle';
      var shapeObject = Shape.getShapeFactory(shapeType);
      var cfg = {
        color: item.color
      };
      var marker = shapeObject.getMarkerCfg(shape, cfg);
      return markerOption(marker, item);
    }

    return _extends({
      fill: item.color
    }, markerOption);
  };

  return TooltipController;
}();

module.exports = TooltipController;