<!--
 * @Author: 曹捷
 * @Date: 2020-08-11 11:33:38
 * @LastEditors: 曹捷
 * @LastEditTime: 2021-06-08 12:34:22
 * @Description: 流程图  一级组件 ，流程图核心
-->
<template>
  <div @contextmenu.prevent="panleContextmenu" @dragover="dragoverHandle" @drop="dropHandle" @mousedown="initDrag"
    @mousemove="startDrag" @mouseup="endDrag" class="mainContainer scrollBar" :class="{'moveContainer':dragInfo.init}"
    id="mainContainer">
    <div :class="{ 'flow-main-content': flowType !== 'show' ,'showAllPoint':moveLine }" :id="flowID"
      :style="{ width: panelInfo.width, height: panelInfo.height }" @click="clickBgHandle" class="flow-main">
      <div :style="{ left: moveInfo.x + 'px' }" class="line-x" v-show="moveInfo.x"></div>
      <div :style="{ top: moveInfo.y + 'px' }" class="line-y" v-show="moveInfo.y"></div>
      <flowNode :index="index" :itemInfo="item" :key="'node-'+item.mainData.uuid" :ref="''+item.mainData.uuid"
        :type="flowType" v-for="(item, index) in nodeList" :class="item.mainData.comptId">
        <template #default="{data}">
          <slot name="node" :data="data" :index="index"></slot>
        </template>
      </flowNode>
    </div>
  </div>
</template>

<script>
import flowNode from './flowNode.vue'
import { targetEndpoint, sourceEndpoint } from './style'
import instance from './instance.js'
import layout from './layout.js'
import { mapGetters } from 'vuex'
import './store.js'
import movePanZoom from './panzoom.js'
import util from './../../utils/utils'
export default {
  components: { flowNode },
  props: {
    initData: {
      type: Array,
    },
    flowType: {
      type: String,
      default: 'add',
    },
    panelInit: {
      type: Object,
    },
  },
  provide() {
    return { panelOption: this.panelOption }
  },
  computed: {
    ...mapGetters('flowlayout', ['nodeList', 'targetNodeId']),
    panelInfo() {
      let width = this.panelInit ? this.panelInit.width : this.panelOption.width
      let height = this.panelInit
        ? this.panelInit.height
        : this.panelOption.height
      return { width, height }
    },
    /**
     * 当前移动的组件坐标
     * 监听移动的流程块位置，计算虚拟坐标线
     * */
    moveInfo() {
      let res = {}
      let x = this.panelOption.movePos[0]
      let y = this.panelOption.movePos[1]
      let uuid = this.panelOption.uuid
      // 计算的坐标条件有   当前节点的四条边  和目标节点的四条边  一一比对是否是一个水平
      let dom = document.getElementById(uuid)
      if (!dom || (x ===0 && y ===0)) {
        return res
      }
      let domX = dom.offsetWidth,
        domY = dom.offsetHeight
      let width, num, height
      for (const item of this.nodeList) {
        let domc = document.getElementById(item.mainData.uuid)
        if(!domc){
          res.x= 0
          continue
        }
        width = domc.offsetWidth
        num = parseInt(item.mainData.pageX.replace('px', ''))
        if (item.mainData.uuid !== uuid) {
          if (num === x || num + width === x) {
            res.x = x
            break
          } else if (num === x + domX || num + width === x + domX) {
            res.x = x + domX
            break
          }
        }
      }
      for (const item of this.nodeList) {
         let domc = document.getElementById(item.mainData.uuid)
        if(!domc){
          res.y = 0
          continue
        }
        height = domc.offsetHeight
        num = parseInt(item.mainData.pageY.replace('px', ''))
        // console.log(1,domc,height,num,uuid ,y , domY)
        if (item.mainData.uuid !== uuid) {
          if (num === y || num + height === y) {
            res.y = y
            break
          } else if (num === y + domY || num + height === y + domY) {
            res.y = y + domY
            break
          }
        }
      }
      return res
    },
  },
  data() {
    return {
      isShowNode: false,
      panelOption: {
        width: '100%',
        height: '100%',
        uuid: '',
        movePos: [],
      },
      flowID: 'flowMain-' + new Date().getTime(),
      // 滚动条移动判断参数
      dragInfo: {},
      // 流程连线的时候，显示所有的流程节点
      moveLine: false,
    }
  },
  watch: {
    // 设置选中节点信息
    targetNodeId(targetId, lastId) {
      if (targetId && targetId !== lastId) {
        let points = instance.getEndpoints(document.getElementById(targetId))
        points.forEach((element) => {
          element.canvas.classList.add('pointShow')
        })
      }
      if (lastId && document.getElementById(lastId)) {
        let lastPoints = instance.getEndpoints(document.getElementById(lastId))
        lastPoints.forEach((element) => {
          element.canvas.classList.remove('pointShow')
        })
      }
    },
  },
  methods: {
    init() {
      instance.setContainer(this.flowID)
      this.initShowFlow()
      this.bindEvent()
      let dom = document.getElementById(this.flowID)
      this.panelOption.width = `${dom.offsetWidth}px`
      this.panelOption.height = `${dom.offsetHeight}px`
    },
    // 禁止画板 浏览器 右键菜单弹出
    panleContextmenu(event) {
      return false
    },
    // 同步panel大小  大小过小，保持百分比展示
    initPanelSize() {
      setTimeout(() => {
        let dom = document.getElementById('mainContainer')
        // console.log(
        //   'initPanelSize ',
        //   dom.offsetWidth,
        //   this.panelOption.width.replace('px', '')
        // )

        if (dom.offsetWidth > this.panelOption.width.replace('px', '')) {
          this.panelOption.width = `${dom.offsetWidth}px`
        }
        if (dom.offsetHeight > this.panelOption.height.replace('px', '')) {
          this.panelOption.height = `${dom.offsetHeight}px`
        }
      }, 350)
      // element  transition 动画0.3s
    },
    // 点击任何地方可以拖动页面滚动条
    initDrag(event) {
      this.$store.commit('flowlayout/setTargetNodeId', '')
      this.dragInfo.scrollLeft = this.$el.scrollLeft
      this.dragInfo.scrollTop = this.$el.scrollTop
      this.dragInfo.screenX = event.screenX
      this.dragInfo.screenY = event.screenY
      this.dragInfo.init = true
    },
    // 按住面板 移动
    startDrag(event) {
      if (this.dragInfo.init) {
        let moveX = event.screenX - this.dragInfo.screenX
        let moveY = event.screenY - this.dragInfo.screenY
        let left = this.dragInfo.scrollLeft - moveX
        let top = this.dragInfo.scrollTop - moveY
        if (left > 0) {
          this.$el.scrollLeft = left
        }
        if (top > 0) {
          this.$el.scrollTop = top
        }
      }
    },
    endDrag(event) {
      this.dragInfo.init = false
    },
    // 流程图回显
    initShowFlow() {
      if (this.initData) {
        this.$store.commit('flowlayout/setNodeList', this.initData)
        // this.nodeList = this.initData
      }
      // 流程只展示查看 不可以编辑
      if (this.flowType === 'show') {
        let i = new movePanZoom(instance.getContainer())
        i.setInstall(i)
        // console.log('initShowFlow -> i', i)

        instance.Defaults.ReattachConnections = true //是否重新连接使用鼠标分离的线
      }
    },
    // 同步坐标
    sysnChartPostion() {
      this.nodeList.forEach((element) => {
        let dom = document.getElementById(element.mainData.uuid).style
        element.mainData.pageX = dom.left
        element.mainData.pageY = dom.top
      })
    },
    // 保存 获取所有节点信息和面板信息
    getFlowLine() {
      this.sysnChartPostion()
      let lines = instance.getAllConnections()
      // let dataList = util.util.cloneObj(this.nodeList)
      this.nodeList.forEach((element) => {
        // 当前节点是否有上级
        let prev = util.array.clearNull(
          lines.map((item) => {
            if (item.targetId === element.mainData.uuid) {
              return item.sourceId
            }
          })
        )
        let next = util.array.clearNull(
          lines.map((item) => {
            if (item.sourceId === element.mainData.uuid) {
              return {
                uuid: item.targetId,
                souceType: item.endpoints[0].anchor.type,
                targetType: item.endpoints[1].anchor.type,
              }
            }
          })
        )
        Object.assign(element, { prev, next })
        // let info = { mainData, prev, next }
        // lineList.push(info)
      })
      let flowLine = util.util.cloneObj(this.nodeList)
      let panelOption = util.util.cloneObj(this.panelOption)
      return { flowLine, panelOption }
    },
    dragoverHandle(ev) {
      ev.preventDefault()
    },
    // 拖拽组件进入面板
    dropHandle(ev) {
      let comptId = ev.dataTransfer.getData('id')
      let nodeName = ev.dataTransfer.getData('name')
      if (comptId) {
        let defultConfig = {
          //   被连接点
          targetAnchors: ['TopCenter', 'LeftMiddle'],
          // 连接点
          sourceAnchors: ['BottomCenter', 'RightMiddle'],
        }
        let pagex = ev.pageX - this.$el.offsetLeft

        pagex = Math.round(pagex / 10) * 10
        let pageY = ev.pageY - this.$el.offsetTop
        pageY = Math.round(pageY / 10) * 10
        let params = {
          comptId,
          flowId: this.$route.query.flowId,
        }

        // console.log('🚀 ~ file: flowC pHandle ~ name', comptId)
        if (comptId.indexOf('end') !== -1) {
          defultConfig.targetAnchors = defultConfig.targetAnchors.concat(
            defultConfig.sourceAnchors
          )
          defultConfig.sourceAnchors = []
        }
        // 拖拽组件进入面板，保存对应组件和流程绑定
        this.$store.commit('flowlayout/addNodeList', {
          mainData: Object.assign(defultConfig, {
            pageX: `${pagex}px`,
            pageY: `${pageY}px`,
            comptId,
            nodeName,
            uuid: '' + util.util.uuid(),
          }),
        })
      }
    },
    addCompentInFlow(params) {},
    bindEvent() {
      let _this = this
      // 连线开始，准备连接source点 显示所有的source点
      instance.bind('connectionDrag', function (info, originalEvent) {
        _this.moveLine = true
      })
      // 连线结束，隐藏所有source点
      instance.bind('connectionDragStop', function (info, originalEvent) {
        setTimeout(() => {
          _this.moveLine = false
        }, 1000)
      })
      instance.bind('contextmenu', function (component, originalEvent) {
        _this.$confirm({
          title: '是否删除当前连接线？',
          onOk() {
            instance.deleteConnection(component)
          },
        })
      })
    },
    clickBgHandle() {
      this.isShowNode = false
    },
    getInstance() {
      return instance
    },
    // removeNode(index) {
    // instance.remove(this.itemInfo.mainData.uuid)
    //   this.$store.commit('flowlayout/removeNodeList', index)
    // },
    // 开始执行
    startMove() {
      this.getFlowLine()
      let list = this.nodeList
      let item = list.find((item) => {
        return item.prev.length === 0 && item.next.length > 0
      })
      let lines = instance.getAllConnections()
      let _this = this
      return new Promise((rej, fail) => {
        let startNum = 0
        startCompont(item)
        function startCompont(cptItem) {
          startNum++
          _this.$refs[cptItem.mainData.uuid].activeStart()
          // 模拟数据进行请求
          // 也可以将请求放在node组件里面执行
          setTimeout(() => {
            _this.$refs[cptItem.mainData.uuid].activeEnd()
            let hasKeys = {}
            cptItem.next.forEach((element) => {
              hasKeys[element.uuid] = element.uuid
            })
            Object.keys(hasKeys).forEach((element) => {
              startCompont(
                list.find((item) => {
                  return item.mainData.uuid === element
                })
              )
            })
            startNum--
            if (startNum === 0) {
              rej()
            }
          }, 5000)
        }
      })
    },
    autoLayout() {
      console.log('autoLayout -> autoLayout')
      let info = new layout(this.flowID, this.nodeList)
      instance.repaintEverything() //重绘
      console.log('autoLayout -> info', info)
    },
    clearAll() {
      instance.empty(this.flowID)
      instance.unbind('connectionDrag')
      instance.unbind('connectionDragStop')
      instance.unbind('connectionAborted')
      instance.unbind('contextmenu')
    },
  },
  mounted() {
    this.init()
  },
  beforeUnmount() {
    this.clearAll()
  },
}
</script>

<style lang="less">
.mainContainer.moveContainer {
  cursor: -webkit-grabbing;
}
.mainContainer {
  cursor: -webkit-grab;
}
.showAllPoint {
  .targetPoint.jtk-droppable {
    opacity: 1;
  }
}
.flow-main-content {
  background-image: linear-gradient(
      90deg,
      rgba(180, 180, 180, 0.15) 10%,
      rgba(0, 0, 0, 0) 10%
    ),
    linear-gradient(rgba(180, 180, 180, 0.15) 10%, rgba(0, 0, 0, 0) 10%);
  background-size: 10px 10px;
  .jtk-droppable {
    opacity: 0;
  }
  .pointShow {
    opacity: 1;
  }
  .line-x {
    position: absolute;
    width: 1px;
    height: 100%;
    top: 0;
    bottom: 0;
    background: #29d5cdd6;
    z-index: 1;
  }
  .line-y {
    position: absolute;
    height: 1px;
    left: 0;
    right: 0;
    background: #29d5cdd6;
    z-index: 1;
  }
}
.flow-main {
  .sourcePoint .tooltip {
    .tooltip-arrow {
      width: 0;
      height: 0;
      border-left: 6px solid transparent;
      border-right: 6px solid transparent;
      border-bottom: 8px solid black;
      margin: 0 auto;
    }
    .tooltip-inner {
      background: black;
      color: #fff;
      padding: 8px;
      border-radius: 4px;
      white-space: nowrap;
      font-size: 12px;
    }
  }
}

.flow-main .targetPoint .tooltip {
  .tooltip-arrow {
    width: 0;
    height: 0;
    border-left: 6px solid transparent;
    border-right: 6px solid transparent;
    border-top: 8px solid black;
    margin: 0 auto;
    position: absolute;
    bottom: 2px;
  }
  .tooltip-inner {
    background: black;
    color: #fff;
    padding: 8px;
    border-radius: 4px;
    white-space: nowrap;
    font-size: 12px;
    position: relative;
    top: -10px;
  }
}

.fy_node {
  position: absolute;
  border: 1px solid #289de9;
  width: 170px;
  height: 34px;
  line-height: 32px;
  border-radius: 4px;
  font-size: 14px;
  cursor: move;
  box-sizing: border-box;
  background: #fff;
  overflow: hidden;
}
.fy_node.fy_node_selected {
  background: #e2f2ff;
}
.fy_node:hover {
  border-width: 2px;
  line-height: 30px;
  z-index: 10;
}

.fy_node:hover + .jtk-endpoint {
  z-index: 10;
}

.fy_node:hover + .jtk-endpoint + .jtk-endpoint {
  z-index: 10;
}

.fy_node:hover + .jtk-endpoint + .jtk-endpoint + .jtk-endpoint {
  z-index: 10;
}

.fy_node:hover + .jtk-endpoint + .jtk-endpoint + .jtk-endpoint + .jtk-endpoint {
  z-index: 10;
}

.fy_node:hover
  + .jtk-endpoint
  + .jtk-endpoint
  + .jtk-endpoint
  + .jtk-endpoint
  + .jtk-endpoint {
  z-index: 10;
}

.fy_node:hover
  + .jtk-endpoint
  + .jtk-endpoint
  + .jtk-endpoint
  + .jtk-endpoint
  + .jtk-endpoint
  + .jtk-endpoint {
  z-index: 10;
}

.fy_node .blue_line {
  position: absolute;
  top: 2px;
  left: 3px;
  border-radius: 2px;
  padding: 14px 2px;
  background: #1c9bec;
}
.fy_node:hover .blue_line {
  top: 1px;
  left: 2px;
}
.fy_node .content i {
  position: relative;
  top: -10px;
  color: rgb(0, 205, 234);
  margin-left: 15px;
  margin-right: 15px;
}
.fy_node .content span {
  display: inline-block;
  width: 80px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fy_node:hover .content i {
  margin-left: 14px;
  margin-right: 15px;
  top: -9px;
}
.node-state {
  top: -8px !important;
  font-size: 20px;
  margin-left: 8px !important;
}
.fy_node:hover .node-state {
  top: -7px !important;
  font-size: 20px;
}
.fy_contextMenu {
  margin: 0;
  padding: 5px 0;
  min-width: 170px;
  position: absolute;
  list-style: none;
  background-color: hsla(0, 0%, 100%, 0.98);
  border: 1px solid #eee;
  -webkit-box-shadow: 5px 5px 30px rgba(0, 0, 0, 0.1);
  box-shadow: 5px 5px 30px rgba(0, 0, 0, 0.1);
  border-radius: 2px;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  z-index: 9999;
}
.fy_contextMenu li {
  font-size: 12px;
  color: #333;
  height: 26px;
  line-height: 26px;
  padding-left: 10px;
  padding-right: 10px;
  cursor: pointer;
  -webkit-transition: background-color 0.1s ease;
  -o-transition: background-color 0.1s ease;
  transition: background-color 0.1s ease;
}
.fy_contextMenu li:hover {
  background-color: #e8f6ff;
  color: black;
}
.fy_contextMenu li span {
  margin-left: 10px;
}
.jtk-drag-select * {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
.jtk-endpoint.sourcePoint {
  z-index: 9;
  cursor: crosshair;
}
.jtk-connector {
  cursor: default;
}
.targetPoint.active:not(.jtk-endpoint-connected) svg circle {
  fill: #00cdea;
}
.jtk-connector.active path {
  animation-name: ring;
  animation-duration: 2s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  stroke-dasharray: 5;
}
@keyframes ring {
  from {
    stroke-dashoffset: 50;
  }
  to {
    stroke-dashoffset: 0;
  }
}
</style>