import { __assign } from "tslib";
import { deepMix, clone } from '@antv/util';
import Global from '../global';
export default {
  getDefaultCfg: function getDefaultCfg() {
    return {
      updateEdge: true,
      delegateStyle: {},
      // 是否开启delegate
      enableDelegate: false,
      // 拖动节点过程中是否只改变 Combo 的大小，而不改变其结构
      onlyChangeComboSize: false,
      // 拖动过程中目标 combo 状态样式
      comboActiveState: '',
      selectedState: 'selected'
    };
  },
  getEvents: function getEvents() {
    return {
      'node:dragstart': 'onDragStart',
      'node:drag': 'onDrag',
      'node:dragend': 'onDragEnd',
      'combo:dragenter': 'onDragEnter',
      'combo:dragleave': 'onDragLeave',
      'combo:drop': 'onDropCombo',
      'node:drop': 'onDropNode',
      'canvas:drop': 'onDropCanvas'
    };
  },
  validationCombo: function validationCombo(item) {
    if (!this.origin || !item || item.destroyed) {
      return false;
    }

    var type = item.getType();

    if (type !== 'combo') {
      return false;
    }

    return true;
  },

  /**
   * 开始拖动节点
   * @param evt
   */
  onDragStart: function onDragStart(evt) {
    var _this = this;

    if (!this.shouldBegin.call(this, evt)) {
      return;
    }

    var item = evt.item;

    if (!item || item.destroyed || item.hasLocked()) {
      return;
    } // 如果拖动的target 是linkPoints / anchorPoints 则不允许拖动


    var target = evt.target;

    if (target) {
      var isAnchorPoint = target.get('isAnchorPoint');

      if (isAnchorPoint) {
        return;
      }
    }

    var graph = this.graph;
    this.targets = []; // 将节点拖入到指定的 Combo

    this.targetCombo = null; // 获取所有选中的元素

    var nodes = graph.findAllByState('node', this.selectedState);
    var currentNodeId = item.get('id'); // 当前拖动的节点是否是选中的节点

    var dragNodes = nodes.filter(function (node) {
      var nodeId = node.get('id');
      return currentNodeId === nodeId;
    }); // 只拖动当前节点

    if (dragNodes.length === 0) {
      this.targets.push(item);
    } else if (nodes.length > 1) {
      // 拖动多个节点
      nodes.forEach(function (node) {
        var locked = node.hasLocked();

        if (!locked) {
          _this.targets.push(node);
        }
      });
    } else {
      this.targets.push(item);
    }

    var beforeDragNodes = [];
    this.targets.forEach(function (t) {
      beforeDragNodes.push(clone(t.getModel()));
    });
    this.set('beforeDragNodes', beforeDragNodes);
    this.origin = {
      x: evt.x,
      y: evt.y
    };
    this.point = {};
    this.originPoint = {};
  },

  /**
   * 持续拖动节点
   * @param evt
   */
  onDrag: function onDrag(evt) {
    var _this = this;

    if (!this.origin) {
      return;
    }

    if (!this.shouldUpdate(this, evt)) {
      return;
    }

    if (this.get('enableDelegate')) {
      this.updateDelegate(evt);
    } else {
      this.targets.map(function (target) {
        _this.update(target, evt);
      });
    }
  },

  /**
   * 拖动结束，设置拖动元素capture为true，更新元素位置，如果是拖动涉及到 combo，则更新 combo 结构
   * @param evt
   */
  onDragEnd: function onDragEnd(evt) {
    if (!this.origin || !this.shouldEnd.call(this, evt)) {
      return;
    } // 拖动结束后，设置拖动元素 group 的 capture 为 true，允许拾取拖动元素


    var item = evt.item;

    if (item) {
      var group = item.getContainer();
      group.set('capture', true);
    }

    if (this.delegateRect) {
      this.delegateRect.remove();
      this.delegateRect = null;
    }

    this.updatePositions(evt);
    var graph = this.graph; // 拖动结束后，入栈

    if (graph.get('enabledStack')) {
      var stackData_1 = {
        before: {
          nodes: this.get('beforeDragNodes'),
          edges: [],
          combos: []
        },
        after: {
          nodes: [],
          edges: [],
          combos: []
        }
      };
      this.targets.forEach(function (target) {
        stackData_1.after.nodes.push(target.getModel());
      });
      graph.pushStack('update', clone(stackData_1));
    } // 拖动结束后emit事件，将当前操作的节点抛出去，目标节点为null


    graph.emit('dragnodeend', {
      items: this.targets,
      targetItem: null
    });
    this.point = {};
    this.origin = null;
    this.originPoint = {};
    this.targets.length = 0;
    this.targetCombo = null;
  },

  /**
   * 拖动过程中将节点放置到 combo 上
   * @param evt
   */
  onDropCombo: function onDropCombo(evt) {
    var item = evt.item;
    if (!this.validationCombo(item)) return;
    this.updatePositions(evt);
    var graph = this.graph;

    if (this.comboActiveState) {
      graph.setItemState(item, this.comboActiveState, false);
    }

    this.targetCombo = item; // 拖动结束后是动态改变 Combo 大小还是将节点从 Combo 中删除

    if (this.onlyChangeComboSize) {
      // 拖动节点结束后，动态改变 Combo 的大小
      graph.updateCombos();
    } else {
      var targetComboModel_1 = item.getModel();
      this.targets.map(function (node) {
        var nodeModel = node.getModel();

        if (nodeModel.comboId !== targetComboModel_1.id) {
          graph.updateComboTree(node, targetComboModel_1.id);
        }
      });
      graph.updateCombo(item);
    } // 将节点拖动到 combo 上面，emit事件抛出当前操作的节点及目标 combo


    graph.emit('dragnodeend', {
      items: this.targets,
      targetItem: this.targetCombo
    });
  },
  onDropCanvas: function onDropCanvas(evt) {
    var graph = this.graph;
    if (!this.targets || this.targets.length === 0) return;
    this.updatePositions(evt);

    if (this.onlyChangeComboSize) {
      // 拖动节点结束后，动态改变 Combo 的大小
      graph.updateCombos();
    } else {
      this.targets.map(function (node) {
        // 拖动的节点有 comboId，即是从其他 combo 中拖出时才处理
        var model = node.getModel();

        if (model.comboId) {
          graph.updateComboTree(node);
        }
      });
    }
  },

  /**
   * 拖动放置到某个 combo 中的子 node 上
   * @param evt
   */
  onDropNode: function onDropNode(evt) {
    var self = this;
    if (!self.targets || self.targets.length === 0) return;
    var item = evt.item;
    self.updatePositions(evt);
    var graph = self.graph;
    var comboId = item.getModel().comboId;

    if (comboId) {
      var combo = graph.findById(comboId);

      if (self.comboActiveState) {
        graph.setItemState(combo, self.comboActiveState, false);
      }

      self.targets.map(function (node) {
        var nodeModel = node.getModel();

        if (comboId !== nodeModel.comboId) {
          graph.updateComboTree(node, comboId);
        }
      });
      graph.updateCombo(combo);
    } else {
      self.targets.map(function (node) {
        var model = node.getModel();

        if (model.comboId) {
          graph.updateComboTree(node);
        }
      });
    } // 将节点拖动到另外个节点上面，emit 事件抛出当前操作的节点及目标节点


    graph.emit('dragnodeend', {
      items: self.targets,
      targetItem: item
    });
  },

  /**
   * 将节点拖入到 Combo 中
   * @param evt
   */
  onDragEnter: function onDragEnter(evt) {
    var item = evt.item;
    if (!this.validationCombo(item)) return;
    var graph = this.graph;

    if (this.comboActiveState) {
      graph.setItemState(item, this.comboActiveState, true);
    }
  },

  /**
   * 将节点从 Combo 中拖出
   * @param evt
   */
  onDragLeave: function onDragLeave(evt) {
    var item = evt.item;
    if (!this.validationCombo(item)) return;
    var graph = this.graph;

    if (this.comboActiveState) {
      graph.setItemState(item, this.comboActiveState, false);
    }
  },
  updatePositions: function updatePositions(evt) {
    var _this = this;

    if (!this.targets || this.targets.length === 0) return; // 当开启 delegate 时，拖动结束后需要更新所有已选中节点的位置

    if (this.get('enableDelegate')) {
      this.targets.map(function (node) {
        return _this.update(node, evt);
      });
    }
  },

  /**
   * 更新节点
   * @param item 拖动的节点实例
   * @param evt
   */
  update: function update(item, evt) {
    var origin = this.origin;
    var model = item.get('model');
    var nodeId = item.get('id');

    if (!this.point[nodeId]) {
      this.point[nodeId] = {
        x: model.x || 0,
        y: model.y || 0
      };
    }

    var x = evt.x - origin.x + this.point[nodeId].x;
    var y = evt.y - origin.y + this.point[nodeId].y;
    var pos = {
      x: x,
      y: y
    };

    if (this.get('updateEdge')) {
      this.graph.updateItem(item, pos, false);
    } else {
      item.updatePosition(pos);
    }
  },

  /**
   * 更新拖动元素时的delegate
   * @param {Event} e 事件句柄
   * @param {number} x 拖动单个元素时候的x坐标
   * @param {number} y 拖动单个元素时候的y坐标
   */
  updateDelegate: function updateDelegate(e) {
    var graph = this.graph;

    if (!this.delegateRect) {
      // 拖动多个
      var parent_1 = this.graph.get('group');
      var attrs = deepMix({}, Global.delegateStyle, this.delegateStyle);

      var _a = this.calculationGroupPosition(e),
          cx = _a.x,
          cy = _a.y,
          width = _a.width,
          height = _a.height,
          minX = _a.minX,
          minY = _a.minY;

      this.originPoint = {
        x: cx,
        y: cy,
        width: width,
        height: height,
        minX: minX,
        minY: minY
      }; // model上的x, y是相对于图形中心的，delegateShape是g实例，x,y是绝对坐标

      this.delegateRect = parent_1.addShape('rect', {
        attrs: __assign({
          width: width,
          height: height,
          x: cx,
          y: cy
        }, attrs),
        name: 'rect-delegate-shape'
      }); // this.delegateRect.set('capture', false);
    } else {
      var clientX = e.x - this.origin.x + this.originPoint.minX;
      var clientY = e.y - this.origin.y + this.originPoint.minY;
      this.delegateRect.attr({
        x: clientX,
        y: clientY
      });
    }
  },

  /**
   * 计算delegate位置，包括左上角左边及宽度和高度
   * @memberof ItemGroup
   * @return {object} 计算出来的delegate坐标信息及宽高
   */
  calculationGroupPosition: function calculationGroupPosition(evt) {
    var graph = this.graph;
    var nodes = graph.findAllByState('node', this.selectedState);

    if (nodes.length === 0) {
      nodes.push(evt.item);
    }

    var minx = Infinity;
    var maxx = -Infinity;
    var miny = Infinity;
    var maxy = -Infinity; // 获取已节点的所有最大最小x y值

    for (var i = 0; i < nodes.length; i++) {
      var element = nodes[i];
      var bbox = element.getBBox();
      var minX = bbox.minX,
          minY = bbox.minY,
          maxX = bbox.maxX,
          maxY = bbox.maxY;

      if (minX < minx) {
        minx = minX;
      }

      if (minY < miny) {
        miny = minY;
      }

      if (maxX > maxx) {
        maxx = maxX;
      }

      if (maxY > maxy) {
        maxy = maxY;
      }
    }

    var x = Math.floor(minx);
    var y = Math.floor(miny);
    var width = Math.ceil(maxx) - Math.floor(minx);
    var height = Math.ceil(maxy) - Math.floor(miny);
    return {
      x: x,
      y: y,
      width: width,
      height: height,
      minX: minx,
      minY: miny
    };
  }
};