import { bfsWalk, throttle } from '../utils'
import Base from '../layouts/Base'

// 节点拖动插件
class Drag extends Base {
  //  构造函数
  constructor({ mindMap }) {
    super(mindMap.renderer)
    this.mindMap = mindMap
    this.reset()
    this.bindEvent()
  }

  //  复位
  reset() {
    // 当前拖拽节点
    this.node = null
    // 当前重叠节点
    this.overlapNode = null
    // 当前上一个同级节点
    this.prevNode = null
    // 当前下一个同级节点
    this.nextNode = null
    // 画布的变换数据
    this.drawTransform = null
    // 克隆节点
    this.clone = null
    // 连接线
    this.line = null
    // 同级位置占位符
    this.placeholder = null
    // 鼠标按下位置和节点左上角的偏移量
    this.offsetX = 0
    this.offsetY = 0
    // 克隆节点左上角的坐标
    this.cloneNodeLeft = 0
    this.cloneNodeTop = 0
    // 当前鼠标是否按下
    this.isMousedown = false
    // 拖拽的鼠标位置变量
    this.mouseDownX = 0
    this.mouseDownY = 0
    this.mouseMoveX = 0
    this.mouseMoveY = 0
    // 鼠标移动的距离距鼠标按下的位置距离多少以上才认为是拖动事件
    this.checkDragOffset = 10
  }

  //  绑定事件
  bindEvent() {
    this.checkOverlapNode = throttle(this.checkOverlapNode, 300, this)
    this.mindMap.on('node_mousedown', (node, e) => {
      if (this.mindMap.opt.readonly || node.isGeneralization) {
        return
      }
      if (e.which !== 1 || node.isRoot) {
        return
      }
      e.preventDefault()
      // 计算鼠标按下的位置距离节点左上角的距离
      this.drawTransform = this.mindMap.draw.transform()
      let { scaleX, scaleY, translateX, translateY } = this.drawTransform
      let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
      this.offsetX = x - (node.left * scaleX + translateX)
      this.offsetY = y - (node.top * scaleY + translateY)
      this.node = node
      this.isMousedown = true
      this.mouseDownX = x
      this.mouseDownY = y
    })
    this.mindMap.on('mousemove', e => {
      if (this.mindMap.opt.readonly) {
        return
      }
      if (!this.isMousedown) {
        return
      }
      this.mindMap.emit('node_dragging', this.node)
      e.preventDefault()
      let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
      this.mouseMoveX = x
      this.mouseMoveY = y
      if (
        Math.abs(x - this.mouseDownX) <= this.checkDragOffset &&
        Math.abs(y - this.mouseDownY) <= this.checkDragOffset &&
        !this.node.isDrag
      ) {
        return
      }
      this.mindMap.renderer.clearAllActive()
      this.onMove(x, y)
    })
    this.onMouseup = this.onMouseup.bind(this)
    this.mindMap.on('node_mouseup', this.onMouseup)
    this.mindMap.on('mouseup', this.onMouseup)
  }

  //  鼠标松开事件
  onMouseup(e) {
    if (!this.isMousedown) {
      return
    }
    this.isMousedown = false
    let _nodeIsDrag = this.node.isDrag
    this.node.isDrag = false
    this.node.show()
    this.removeCloneNode()
    // 存在重叠子节点，则移动作为其子节点
    if (this.overlapNode) {
      this.mindMap.renderer.setNodeActive(this.overlapNode, false)
      this.mindMap.execCommand('MOVE_NODE_TO', this.node, this.overlapNode)
    } else if (this.prevNode) {
      // 存在前一个相邻节点，作为其下一个兄弟节点
      this.mindMap.renderer.setNodeActive(this.prevNode, false)
      this.mindMap.execCommand('INSERT_AFTER', this.node, this.prevNode)
    } else if (this.nextNode) {
      // 存在下一个相邻节点，作为其前一个兄弟节点
      this.mindMap.renderer.setNodeActive(this.nextNode, false)
      this.mindMap.execCommand('INSERT_BEFORE', this.node, this.nextNode)
    } else if (_nodeIsDrag && this.mindMap.opt.enableFreeDrag) {
      // 自定义位置
      let { x, y } = this.mindMap.toPos(
        e.clientX - this.offsetX,
        e.clientY - this.offsetY
      )
      let { scaleX, scaleY, translateX, translateY } = this.drawTransform
      x = (x - translateX) / scaleX
      y = (y - translateY) / scaleY
      this.node.left = x
      this.node.top = y
      this.node.customLeft = x
      this.node.customTop = y
      this.mindMap.execCommand('SET_NODE_CUSTOM_POSITION', this.node, x, y)
      this.mindMap.render()
    }
    this.reset()
    this.mindMap.emit('node_dragend')
  }

  //  创建克隆节点
  createCloneNode() {
    if (!this.clone) {
      // 节点
      this.clone = this.node.group.clone()
      this.clone.opacity(0.5)
      this.clone.css('z-index', 99999)
      this.node.isDrag = true
      this.node.hide()
      // 连接线
      this.line = this.draw.path()
      this.line.opacity(0.5)
      this.node.styleLine(this.line, this.node)
      // 同级位置占位符
      this.placeholder = this.draw.rect().fill({
        color: this.node.style.merge('lineColor', true)
      })
      this.mindMap.draw.add(this.clone)
    }
  }

  //  移除克隆节点
  removeCloneNode() {
    if (!this.clone) {
      return
    }
    this.clone.remove()
    this.line.remove()
    this.placeholder.remove()
  }

  //  拖动中
  onMove(x, y) {
    if (!this.isMousedown) {
      return
    }
    this.createCloneNode()
    let { scaleX, scaleY, translateX, translateY } = this.drawTransform
    this.cloneNodeLeft = x - this.offsetX
    this.cloneNodeTop = y - this.offsetY
    x = (this.cloneNodeLeft - translateX) / scaleX
    y = (this.cloneNodeTop - translateY) / scaleY
    let t = this.clone.transform()
    this.clone.translate(x - t.translateX, y - t.translateY)
    // 连接线
    let parent = this.node.parent
    this.line.plot(
      this.quadraticCurvePath(
        parent.left + parent.width / 2,
        parent.top + parent.height / 2,
        x + this.node.width / 2,
        y + this.node.height / 2
      )
    )
    this.checkOverlapNode()
  }

  //  检测重叠节点
  checkOverlapNode() {
    if (!this.drawTransform) {
      return
    }
    let x = this.mouseMoveX
    let y = this.mouseMoveY
    this.overlapNode = null
    this.prevNode = null
    this.nextNode = null
    this.placeholder.size(0, 0)
    bfsWalk(this.mindMap.renderer.root, node => {
      if (node.nodeData.data.isActive) {
        this.mindMap.renderer.setNodeActive(node, false)
      }
      if (node === this.node || this.node.isParent(node)) {
        return
      }
      if (this.overlapNode || (this.prevNode && this.nextNode)) {
        return
      }
      let nodeRect = this.getNodeRect(node)
      let oneFourthHeight = nodeRect.height / 4
      // 前一个和后一个节点
      let checkList = node.parent ? node.parent.children.filter((item) => {
        return item !== this.node
      }) : []
      let index = checkList.findIndex((item) => {
        return item === node
      })
      let prevBrother = null
      let nextBrother = null
      if (index !== -1) {
        if (index - 1 >= 0) {
          prevBrother = checkList[index - 1]
        }
        if (index + 1 <= checkList.length - 1) {
          nextBrother = checkList[index + 1]
        }
      }
      // 和前一个兄弟节点的距离
      let prevBrotherOffset = 0
      if (prevBrother) {
        let prevNodeRect = this.getNodeRect(prevBrother)  
        prevBrotherOffset = nodeRect.top - prevNodeRect.bottom
        // 间距小于10就当它不存在
        prevBrotherOffset = prevBrotherOffset >= 10 ? prevBrotherOffset / 2 : 0
      } else {
        // 没有前一个兄弟节点，那么假设和前一个节点的距离为20
        prevBrotherOffset = 10
      }
      // 和后一个兄弟节点的距离
      let nextBrotherOffset = 0
      if (nextBrother) {
        let nextNodeRect = this.getNodeRect(nextBrother)
        nextBrotherOffset = nextNodeRect.top - nodeRect.bottom
        nextBrotherOffset = nextBrotherOffset >= 10 ? nextBrotherOffset / 2 : 0
      } else {
        nextBrotherOffset = 10
      }
      if (nodeRect.left <= x && nodeRect.right >= x) {
        // 检测兄弟节点位置
        if (!this.overlapNode && !this.prevNode && !this.nextNode && !node.isRoot) {
          let checkIsPrevNode = nextBrotherOffset > 0 ? // 距离下一个兄弟节点的距离大于0
            y > nodeRect.bottom && y <= (nodeRect.bottom + nextBrotherOffset) : // 那么在当前节点外底部判断
            y >= nodeRect.bottom - oneFourthHeight && y <= nodeRect.bottom // 否则在当前节点内底部1/4区间判断
          let checkIsNextNode = prevBrotherOffset > 0 ? // 距离上一个兄弟节点的距离大于0
            y < nodeRect.top && y >= (nodeRect.top - prevBrotherOffset) : // 那么在当前节点外底部判断
            y >= nodeRect.top && y <= nodeRect.top + oneFourthHeight
          if (checkIsPrevNode) {
            this.prevNode = node
            let size = nextBrotherOffset > 0 ? nextBrotherOffset : 5
            this.placeholder.size(node.width, size).move(nodeRect.originLeft, nodeRect.originBottom)
          } else if (checkIsNextNode) {
            this.nextNode = node
            let size = prevBrotherOffset > 0 ? prevBrotherOffset : 5
            this.placeholder.size(node.width, size).move(nodeRect.originLeft, nodeRect.originTop - size)
          }
        }
        // 检测是否重叠
        if (!this.overlapNode && !this.prevNode && !this.nextNode) {
          if (
            nodeRect.top + (prevBrotherOffset > 0 ? 0 : oneFourthHeight) <= y &&
            nodeRect.bottom - (nextBrotherOffset > 0 ? 0 : oneFourthHeight) >= y
          ) {
            this.overlapNode = node
          }
        }
      }
    })
    if (this.overlapNode) {
      this.mindMap.renderer.setNodeActive(this.overlapNode, true)
    }
  }

  // 计算节点的位置尺寸信息
  getNodeRect(node) {
    let { scaleX, scaleY, translateX, translateY } = this.drawTransform
    let { left, top, width, height } = node
    let originLeft = left
    let originTop = top
    let originBottom = top + height
    let right = (left + width) * scaleX + translateX
    let bottom = (top + height) * scaleY + translateY
    left = left * scaleX + translateX
    top = top * scaleY + translateY
    return {
      width,
      height,
      left,
      top,
      right,
      bottom,
      originLeft,
      originTop,
      originBottom
    }
  }
}

Drag.instanceName = 'drag'

export default Drag
