import SeeksGraphMath from '../SeeksGraphMath'

function SeeksBidirectionalTreeLayouter(layoutSetting, graphSetting) {
  this.graphSetting = graphSetting
  this.config = layoutSetting || {}
  if (!this.config.from) this.config.from = 'left'
  if (this.config.levelDistance && typeof this.config.levelDistance === 'string') {
    this.config.levelDistanceArr = this.config.levelDistance.split(',').map(thisNum => parseInt(thisNum))
  }
  this.rootNode = null
  this.allNodes = []
  this.__origin_nodes = []
  this.refresh = function () {
    this.placeNodes(this.__origin_nodes, this.rootNode)
  }
  this.analysisNodes4Didirectional = function (willLayoutNodes, thisLevelNodes, thisDeep, analyticResult, levelDirect) {
    //debugger;
    if (thisLevelNodes.length > analyticResult.max_length) {
      analyticResult.max_length = thisLevelNodes.length
    }
    if (thisDeep > analyticResult.max_deep) {
      analyticResult.max_deep = thisDeep
    }
    var __thisLOT_subling = {
      level: thisDeep,
      all_size: thisLevelNodes.length,
      all_strength: 0
    }
    var newLevelNodes = []
    thisLevelNodes.forEach(thisNode => {
      if (!thisNode.lot) thisNode.lot = {}
      thisNode.lot.eached = true
      thisNode.lot.subling = __thisLOT_subling
      thisNode.lot.level = thisDeep
      willLayoutNodes.push(thisNode)
    })
    var __thisLevel_index = 0
    thisLevelNodes.forEach(thisNode => {
      var __thisNode_child_size = 0
      if (levelDirect === -1) {
        let __thisTargetIndex = 0
        thisNode.targetFrom.forEach((thisTarget) => {
          if (!thisTarget.lot) thisTarget.lot = {
            eached: false
          }
          if (!thisTarget.lot.eached) {
            if (SeeksGraphMath.isAllowShowNode(thisTarget)) {
              thisTarget.lot.eached = true
              thisTarget.lot.parent = thisNode
              thisTarget.lot.index_of_parent = __thisTargetIndex++
              thisNode.lot.childs.push(thisTarget)
              newLevelNodes.push(thisTarget)
              __thisNode_child_size++
            } else {
              thisNode.lot.childs.push(thisTarget)
            }
          }
        })
      } else {
        let __thisTargetIndex = 0
        thisNode.targetTo.forEach((thisTarget) => {
          if (!thisTarget.lot) thisTarget.lot = {
            eached: false
          }
          if (!thisTarget.lot.eached) {
            if (true) {
              thisTarget.lot.eached = true
              thisTarget.lot.parent = thisNode
              thisTarget.lot.index_of_parent = __thisTargetIndex++
              thisNode.lot.childs.push(thisTarget)
              newLevelNodes.push(thisTarget)
              __thisNode_child_size++
            } else {
              thisNode.lot.childs.push(thisTarget)
            }
          }
        })
        if (thisNode.targetFrom && thisNode.targetFrom.length > 0) {
          thisNode.targetFrom.forEach((thisTarget) => {
            if (!thisTarget.lot) thisTarget.lot = {
              eached: false
            }
            if (!thisTarget.lot.eached && thisTarget.nodeParent) {
              if (SeeksGraphMath.isAllowShowNode(thisTarget)) {
                thisTarget.lot.eached = true
                thisTarget.lot.parent = thisNode
                thisTarget.lot.index_of_parent = __thisTargetIndex++
                thisNode.lot.childs.push(thisTarget)
                newLevelNodes.push(thisTarget)
              } else {
                thisNode.lot.childs.push(thisTarget)
                newLevelNodes.push(thisTarget)
              }
            }
          })
        }
      }
      thisNode.lot.strength = __thisNode_child_size > 0 ? __thisNode_child_size : 1
      __thisLOT_subling.all_strength += thisNode.lot.strength
      thisNode.lot.strength_plus = __thisLOT_subling.all_strength
      thisNode.lot.index_of_level = __thisLevel_index
      thisNode.lot.childs_size = __thisNode_child_size
      __thisLevel_index++
    })
    if (__thisLOT_subling.all_strength > analyticResult.max_strength) {
      analyticResult.max_strength = __thisLOT_subling.all_strength
    }
    if (newLevelNodes.length > 0) {
      this.analysisNodes4Didirectional(willLayoutNodes, newLevelNodes, thisDeep + levelDirect, analyticResult, levelDirect)
    } else {
      willLayoutNodes.forEach(thisNode => {
        if (thisNode.lot.childs_size > 0) {

          thisNode.lot.strengthWithChilds = 0
        }
      })
      willLayoutNodes.forEach(thisNode => {

        if (thisNode.lot.childs_size === 0) {
          thisNode.lot.strengthWithChilds = 1
          SeeksGraphMath.conductStrengthToParents(thisNode)
        }
      })
      SeeksGraphMath.analysisDataTree([willLayoutNodes[0]], 0, levelDirect)
    }
  }
  this.placeNodes = function (allNodes, rootNode) {
    if (!rootNode) {
      console.error('root is null')
      return
    } 
    this.__origin_nodes = allNodes
    this.rootNode = rootNode
    allNodes.forEach(thisNode => {
      thisNode.lot.eached = false
      thisNode.lot.notLeafNode = false
      thisNode.lot.childs = []
      thisNode.lot.index_of_parent = 0
      thisNode.lot.strength = 0
      thisNode.lot.strengthWithChilds_from = 0
      thisNode.lot.strengthWithChilds = 0
      thisNode.lot.prevNode = undefined
      thisNode.lot.nextNode = undefined
      thisNode.lot.placed = false
    })
    this.allNodes = []
    var analyticResult = {
      max_deep: 1,
      max_length: 1,
      max_strength: 1
    }
    this.analysisNodes4Didirectional(this.allNodes, [this.rootNode], 0, analyticResult, -1)
    this.placeNodesPosition(this.rootNode, this.allNodes, analyticResult)
    this.allNodes = []
    analyticResult = {
      max_deep: 1,
      max_length: 1,
      max_strength: 1
    }
    this.analysisNodes4Didirectional(this.allNodes, [this.rootNode], 0, analyticResult, 1)
    this.placeNodesPosition(this.rootNode, this.allNodes, analyticResult)
  }
  this.placeNodesPosition = function (rootNode, allNodes, analyticResult) {
    var __mapWidth = this.graphSetting.viewSize.width
    var __mapHeight = this.graphSetting.viewSize.height
    var __offsetX = rootNode.offset_x || 0
    var __offsetY = rootNode.offset_y || 0
    if (rootNode.fixed !== true) {
      var _center_offset_x = parseInt(this.config.centerOffset_x) || 0
      var _center_offset_y = parseInt(this.config.centerOffset_y) || 0
      if (this.config.from === 'top') {
        rootNode.lot.x = (__mapWidth - rootNode.el.offsetWidth) / 2 + _center_offset_x
        rootNode.lot.y = parseInt(__mapHeight * 0.3 - rootNode.el.offsetHeight) + _center_offset_y
      } else if (this.config.from === 'bottom') {
        rootNode.lot.x = (__mapWidth - rootNode.el.offsetWidth) / 2 + _center_offset_x
        rootNode.lot.y = parseInt(__mapHeight * 0.7 - rootNode.el.offsetHeight) + _center_offset_y
      } else if (this.config.from === 'right') {
        rootNode.lot.x = parseInt(__mapWidth * 0.7 - rootNode.el.offsetWidth) / 2 + _center_offset_x
        rootNode.lot.y = parseInt(__mapHeight / 2 - rootNode.el.offsetHeight / 2) + _center_offset_y
      } else {
        rootNode.lot.x = parseInt(__mapWidth * 0.3 - rootNode.el.offsetWidth) / 2 + _center_offset_x
        rootNode.lot.y = parseInt(__mapHeight / 2 - rootNode.el.offsetHeight / 2) + _center_offset_y
      }
      rootNode.x = rootNode.lot.x + __offsetX
      rootNode.y = rootNode.lot.y + __offsetY
    } else {
      if (rootNode.origin_x === undefined) {
        rootNode.origin_x = rootNode.x
        rootNode.origin_y = rootNode.y
      }
      rootNode.lot.x = rootNode.origin_x
      rootNode.lot.y = rootNode.origin_y
      rootNode.x = rootNode.lot.x + __offsetX
      rootNode.y = rootNode.lot.y + __offsetY
    }
    rootNode.lot.placed = true
    var dynamicSizeConfig = {
      __mapWidth,
      __mapHeight
    }
    this.placeRelativePosition(rootNode, analyticResult, dynamicSizeConfig)
    let mainNodes = allNodes.filter(x => x.id.indexOf('main') != -1)
    let maxlevel = 0
    //计算种子
    mainNodes.forEach(thisNode => {
      let temp = allNodes.filter(x => x.targetTo && x.targetTo.length > 0 && x.targetTo[0].id == thisNode.id && x.nodeParent)
      if (temp && temp.length > 1) {
        allNodes.forEach(x => {
          if (x.lot.level > maxlevel) {
            maxlevel = x.lot.level
          }
          if (x.id == thisNode.id) {
            x.parentNum = temp.length
          }
        })
      }
    })
    let zongHeight = 0
    mainNodes.forEach(thisNode => {
      let parentNodes = allNodes.filter(x => x.nodeParent && x.lot.parent && x.lot.parent.id == thisNode.id && x.isShow)
      if (parentNodes) {
        let sumHeight = 0
        parentNodes.forEach(x => {
          let maxHeight = 1
          for (let i = maxlevel; i > 2; i--) {
            let levelCount = allNodes.filter(y => y.rootId == x.id && y.lot.level == i && y.isShow)
            if (levelCount && levelCount.length > maxHeight) {
              maxHeight = levelCount.length
            }
          }
          sumHeight += maxHeight
          x.maxHeight = maxHeight
        })
        thisNode.align = 'left'
        thisNode.maxHeight = sumHeight
        zongHeight += sumHeight
      }
    })
    let rightZongHeight = 0
    mainNodes.forEach(thisNode => {
      let parentNodes = allNodes.filter(x => !x.nodeParent && x.lot.parent && x.lot.parent.id == thisNode.id && x.isShow)
      if (parentNodes) {
        let sumHeight = 0
        parentNodes.forEach(x => {
          let maxHeight = 1
          for (let i = maxlevel; i > 2; i--) {
            let levelCount = allNodes.filter(y => y.rightRootId == x.id && y.lot.level == i && y.isShow)
            if (levelCount && levelCount.length > maxHeight) {
              maxHeight = levelCount.length
            }
          }
          sumHeight += maxHeight
          x.maxHeight = maxHeight //>x.maxHeight?maxHeight:x.maxHeight
        })
        if (thisNode.maxHeight <= sumHeight) {
          thisNode.leftMaxHeight = thisNode.maxHeight
          thisNode.maxHeight = sumHeight
          thisNode.align = 'right'
        } else {
          thisNode.rightMaxHeight = sumHeight
        }
        rightZongHeight += sumHeight
      }
    })
    zongHeight = rightZongHeight > zongHeight ? rightZongHeight : zongHeight
    //计算偏移量
    if (zongHeight >= 0 && mainNodes.length > 0) {
      zongHeight = zongHeight < mainNodes.length ? mainNodes.length : zongHeight
      let beginY = rootNode.lot.y - (zongHeight * 100 / 2) //((mainNodes[mainNodes.length-1].lot.y-mainNodes[0].lot.y)/2)+(zongHeight*100/2)
      mainNodes.forEach((thisNode) => {
        if (zongHeight > 0) {
          let parentNodes = allNodes.filter(x => x.nodeParent && x.lot.parent.id == thisNode.id && x.isShow)
          let tempBeginY = beginY
          if (thisNode.align == 'right') {
            tempBeginY = beginY + ((thisNode.maxHeight - thisNode.leftMaxHeight) * 50)
          }
          parentNodes.forEach(x => {
            tempBeginY += x.maxHeight * 100 / 2
            x.lot.y = tempBeginY
            tempBeginY += x.maxHeight * 100 / 2
          })

          let rparentNodes = allNodes.filter(x => !x.nodeParent && x.lot.parent && x.lot.parent.id == thisNode.id && x.isShow)
          let rtempBeginY = beginY
          if (thisNode.align == 'left') {
            rtempBeginY = beginY + ((thisNode.maxHeight - thisNode.rightMaxHeight) * 50)
          }
          rparentNodes.forEach(x => {
            rtempBeginY += x.maxHeight * 100 / 2
            x.lot.y = rtempBeginY
            rtempBeginY += x.maxHeight * 100 / 2
          })
        }
        thisNode.maxHeight = thisNode.maxHeight == 0 ? 1 : thisNode.maxHeight
        beginY += thisNode.maxHeight * 100 / 2
        thisNode.lot.y = beginY
        beginY += thisNode.maxHeight * 100 / 2
      })
    }
    allNodes.forEach(x => {
      if (!x.isShow) return;
      if (x.rightNode) {
        let parentNode = x.lot.parent
        //获取上级坐标
        let tempX = parentNode.lot.x - 420
        let tempY = parentNode.lot.y
        let index = parentNode.lot.childs.indexOf(x)
        tempY = (tempY - ((parentNode.lot.childs.length - 1) * 100 / 2)) + (100 * index)
        x.lot.y = tempY
        if (x.rightNode) {
          x.lot.x = tempX
        }
      } else if (x.id.indexOf('child') != -1 && x.lot.parent && x.lot.parent.id.indexOf("main") == -1) {
        let parentNode = x.lot.parent
        if (parentNode) {
          let tempY = parentNode.lot.y
          let index = x.lot.index_of_parent
          tempY = (tempY - ((parentNode.lot.childs.length - 1) * 100 / 2)) + (100 * index)
          x.lot.y = tempY
        }
      }
    })
    allNodes.forEach(thisNode => {
      if (thisNode.nodeParent) {
        thisNode.lot.x = thisNode.targetTo[0].lot.x - 420
      }
      if (thisNode.fixed === true) {
        thisNode.lot.placed = true
        return
      }

      if (!SeeksGraphMath.isAllowShowNode(thisNode)) return
      var __offsetX = thisNode.offset_x || 0
      var __offsetY = thisNode.offset_y || 0
      thisNode.x = thisNode.offset_x + thisNode.lot.x + __offsetX
      thisNode.y = thisNode.offset_y + thisNode.lot.y + __offsetY
      thisNode.lot.placed = true
    })

  }
  this.placeRelativePosition = function (rootNode, analyticResult, dynamicSizeConfig) {
    if (this.config.from === 'left' || this.config.from === 'right') {
      const __min_per_height = this.config.min_per_height || 80
      const __max_per_height = this.config.max_per_height || 400
      const __min_per_width = this.config.min_per_width || 430
      const __max_per_width = this.config.max_per_width || 650
      let __per_width = parseInt((dynamicSizeConfig.__mapWidth - 10) / (analyticResult.max_deep + 2))
      if (__per_width < __min_per_width) __per_width = __min_per_width
      if (__per_width > __max_per_width) __per_width = __max_per_width
      let __per_height = parseInt(dynamicSizeConfig.__mapHeight / (analyticResult.max_strength + 1))
      if (__per_height < __min_per_height) __per_height = __min_per_height
      if (__per_height > __max_per_height) __per_height = __max_per_height
      this.allNodes.forEach(thisNode => {
        if (thisNode.nodeParent) return;
        if (thisNode.fixed === true) return
        if (thisNode.lot.placed === true) return
        if (thisNode === rootNode) return
       
        if (this.config.from === 'right') {
          thisNode.lot.x = rootNode.lot.x - this.getLevelDistance(thisNode, thisNode.lot.subling.level, __per_width)
        } else {

          thisNode.lot.x = rootNode.lot.x + this.getLevelDistance(thisNode, thisNode.lot.subling.level, __per_width)
        }

      })
      this.allNodes.forEach(thisNode => {
        if (thisNode.fixed === true || this.nodeParent) return
        if (thisNode.lot.level !== 0) {
          thisNode.lot.y = rootNode.lot.y + __per_height * ((analyticResult.max_strength / -2) + thisNode.lot.strengthWithChilds_from + thisNode.lot.strengthWithChilds / 2)
        }
      })
      // this.allNodes.forEach(thisNode => {
      //   if (thisNode.fixed === true) return
      //   if (thisNode.lot.level === 1) {
      //     thisNode.lot.y = __per_height * (thisNode.lot.strength_plus - thisNode.lot.strength + (thisNode.lot.strength - 1) / 2)
      //   }
      // })
      // this.allNodes.forEach(thisNode => {
      //   if (thisNode.fixed === true) return
      //   if (thisNode.lot.level > 1) {
      //     // thisNode.lot.y = __per_height * (thisNode.lot.strength_plus - thisNode.lot.strength + (thisNode.lot.strength - 1) / 2)
      //     thisNode.lot.y = __per_height * (thisNode.lot.parent.lot.strength_plus - thisNode.lot.parent.lot.strength + thisNode.lot.index_of_parent)
      //     // thisNode.text = thisNode.lot.parent.lot.strength_plus + '-' + thisNode.lot.parent.lot.strength + '+' + thisNode.lot.index_of_parent
      //   }
      // })
    } else {
      const __min_per_height = this.config.min_per_height || 250
      const __max_per_height = this.config.max_per_height || 400
      const __min_per_width = this.config.min_per_width || 250
      const __max_per_width = this.config.max_per_width || 500
      var __per_width = parseInt((dynamicSizeConfig.__mapWidth - 10) / (analyticResult.max_strength + 2))
      if (__per_width < __min_per_width) __per_width = __min_per_width
      if (__per_width > __max_per_width) __per_width = __max_per_width
      var __per_height = parseInt((dynamicSizeConfig.__mapHeight - 10) / (analyticResult.max_deep + 2))
      if (__per_height < __min_per_height) __per_height = __min_per_height
      if (__per_height > __max_per_height) __per_height = __max_per_height
      this.allNodes.forEach(thisNode => {
        if (thisNode.fixed === true || this.nodeParent) return
        if (thisNode.lot.placed === true) return
        if (thisNode === rootNode) return
       
        if (this.config.from === 'bottom') {
          thisNode.lot.y = rootNode.lot.y - this.getLevelDistance(thisNode, thisNode.lot.subling.level, __per_height)
        } else {
        
          thisNode.lot.y = rootNode.lot.y + this.getLevelDistance(thisNode, thisNode.lot.subling.level, __per_height)
        }
      })
      this.allNodes.forEach(thisNode => {
        if (thisNode.fixed === true || this.nodeParent) return
        if (thisNode.lot.level !== 0) {
          thisNode.lot.x = -58 + rootNode.lot.x + __per_width * ((analyticResult.max_strength / -2) + thisNode.lot.strengthWithChilds_from + thisNode.lot.strengthWithChilds / 2)
        }
      })
    }
  }
  this.getLevelDistance = function (node, level, perSize) {
    if (this.config.levelDistanceArr && this.config.levelDistanceArr.length > 0) {
      var _distance = 0
      for (let i = 0; i < level; i++) {
        var _thisLevelDistance = this.config.levelDistanceArr[i] || 100
        _distance += _thisLevelDistance
      }
      return _distance
    } else {
      return level * perSize
    }
  }
}

export default SeeksBidirectionalTreeLayouter
