/* global isIE isGecko Dialog $D $DW Util DataCollection */
const indicatorArr = []
const commentArr = []
const textNodeArr = []
const fragForIndicators = document.createDocumentFragment()
const lastModifiedTags = []
const modifiedTags = []
const TagURLMap = {}
var EditMode

const editorJs = {
  rectIntersect (rect1, rect2) {
    // 修正变量名
    let t = Math.max(rect1.top, rect2.top)

    let r = Math.min(rect1.right, rect2.right)

    let b = Math.min(rect1.bottom, rect2.bottom)

    let l = Math.max(rect1.left, rect2.left)

    if (b >= t && r >= l) {
      return {
        top: t,
        right: r,
        bottom: b,
        left: l
      }
    } else {
      return null
    }
  },
  needFilter (node) {
    let tagName = node.tagName
    if (!tagName) {
      return true
    }
    if (/^(head|meta|script|link|style|area|param)$/i.test(tagName)) {
      return true
    }
    return false
  },

  isVisible (node) {
    if (node.offsetWidth === 0 && node.offsetHeight === 0 && node.tagName !== 'TR') {
      return false
    }
    if (node.currentStyle && node.currentStyle.display === 'none') {
      return false
    }
    return true
  },
  findAll (ele) {
    let nodes = ele.childNodes
    let textNodeFlag = true
    let tagStartCount = 0
    for (let i = 0; i < nodes.length; i++) {
      let node = nodes[i]
      if (node.nodeType === 1) {
        textNodeFlag = false
        if (node.hasChildNodes()) {
          this.findAll(node)
        }
      } else if (node.nodeType === 8) {
        if (node.nodeValue.startsWith('_TAGSTART_')) {
          commentArr.push(node)
          tagStartCount++
        }
        if (node.nodeValue.startsWith('_TAGEND_')) {
          commentArr.push(node)
          tagStartCount--
        }
      }
    }
    if (textNodeFlag && tagStartCount === 0 && !this.needFilter(ele)) {
      ele.contentEditable = true
      ele.OldInnerHTML = ele.innerHTML
      textNodeArr.push(ele)
    }
  },
  trans2dom (val) {
    let div = document.createElement('div')
    if (typeof val === 'string') {
      div.innerHTML = val
    }
    return div
  },
  addIndicator (val) {
    if (indicatorArr.length > 0) {
      return
    }
    let bodyContent = this.trans2dom(val)
    this.findAll(bodyContent)
    for (let i = 0; i < commentArr.length; i++) {
      let node = commentArr[i]
      let txt = node.nodeValue
      if (!txt.startsWith('_TAGSTART_')) {
        continue
      }
      let next = node.nextSibling
      let id = txt.substring(10, txt.indexOf(':'))
      let endTags = '_TAGEND_' + id
      // console.log('next:'+txt+'id:'+id)
      while (next && (next.nodeType !== 1 || this.needFilter(next) || !this.isVisible(next))) {
        // if(next.nodeType ==8 && next.nodeValue.startsWith("_TAGS")){//2014-08-05 发现广告占位看不见，但错误地显示了Indicator
        if (next.nodeType === 8 && next.nodeValue === endTags) {
          break
        } else if (next.nodeType === 8 && next.nodeValue.startsWith('_TAG')) {
          // 如果遇到下一个节点前还没有找到可见节点
          next = null
          break
        }
        next = next.nextSibling
      }
      if (next === null) {
        continue
      }
      let endNode = null
      for (let j = i + 1; j < commentArr.length; j++) {
        if (commentArr[j].nodeValue.indexOf(id) === 8) {
          endNode = commentArr[j]
          break
        }
      }
      if (endNode === null) {
        continue
      }
      let previous = endNode.previousSibling
      while (previous && (previous.nodeType !== 1 || this.needFilter(previous) || !this.isVisible(previous))) {
        previous = previous.previousSibling
      }
      if (previous === null) {
        continue
      }
      // console.log('next:'+next+'previous:'+previous+'node:'+node)
      this.initTagIndicator(next, previous, node)
    }
    // document.body.appendChild(fragForIndicators);
    this.setIndicatorPosition()
    // alert(new Date().getTime()-t);
    // EventManager.onWindowResize(resetIndicatorPosition);
  },
  resetIndicatorPosition () {
    $('div.z-edit-add-box').forEach(val => {
      if (val.style.left !== '-999px' && val._ofEl) {
        let ofPos = $(val._ofEl).offset()
        // console.log(ofPos.left);
        val.style.left = ofPos.left + val._offsetLeft + 'px'
        val.style.top = ofPos.top + val._offsetTop + 'px'
      }
    })
    this.setIndicatorPosition()
  },
  initTagIndicator (ele, endEle, commentNode) {
    let txt = commentNode.nodeValue
    if (!txt.startsWith('_TAGSTART_')) {
      return
    }
    txt = txt.substring(10)
    let firstUnderLine = txt.indexOf('_')
    let prefix = txt.substring(0, firstUnderLine)
    txt = txt.substring(firstUnderLine + 1)
    firstUnderLine = txt.indexOf('_')
    let name = txt.substring(0, firstUnderLine)
    let indexes = txt.substring(firstUnderLine + 1, txt.indexOf(':'))
    let attr = txt.substring(txt.indexOf(':') + 1)
    if (!ele || !ele.tagName) {
      if (txt.indexOf('friendlink') > 0) {
      }
      return
    }
    let isVisible = true
    if (isIE) {
      // 下面代码段为解决一个特殊情况，iE下自动结束的块元素(如li标签)会把相邻块元素间的注释解析为自己的子节点
      if (ele.tagName === 'LI' && endEle.parentElement.tagName === 'LI') {
        endEle = endEle.parentElement
      }
    }
    if ((ele.parentElement && !Node.isVisible(ele.parentElement)) || (!Node.isVisible(ele) && !Node.isVisible(endEle))) {
      isVisible = false
    }
    // 判断ele、endEle否是兄弟节点中的起始和结束节点
    let brothers = ele.parentNode.childNodes
    let flag = true
    let i
    if (ele === endEle) {
      flag = false
    } else {
      for (i = 0; i < brothers.length; i++) {
        if (brothers[i].nodeType === 1) {
          if (brothers[i] !== ele) {
            flag = false
          }
          break
        }
      }
      if (flag) {
        for (i = brothers.length - 1; i >= 0; i--) {
          if (brothers[i].nodeType === 1) {
            if (brothers[i] !== endEle) {
              flag = false
            }
            break
          }
        }
      }
    }
    let pos0 = $(ele).offset()
    let dim = Node.getSize(endEle)
    let pos2 = $(endEle).offset()
    if (isGecko) {
      // 下面代码段为解决一个特殊情况，firefox下内联元素(如<a>)内有块元素时，内联元素的起始坐标并不同等同于此块元素的起始坐标
      if (ele.currentStyle.display === 'inline' && ele.children.length) {
        let child0 = ele.children[0]
        if (
          child0.currentStyle.cssFloat === 'left' ||
          (child0.currentStyle.display !== 'inline' && child0.currentStyle.display !== 'none') ||
          /^img|input$/i.test(child0.tagName)
        ) {
          pos0 = $(ele.children[0]).offset()
        }
      }
    }
    let pos1 = {}
    pos1.x = pos1.left = Math.min(pos0.left, pos2.left)
    pos1.y = pos1.top = Math.min(pos0.top, pos2.top)

    let w, h
    if (flag) {
      let p = ele.parentNode
      dim = Node.getContentSize(p)
      w = dim.width
      h = dim.height
    } else {
      let pos2 = $(endEle).offset()
      w = pos2.left - pos1.left + dim.width
      h = pos2.top - pos1.top + dim.height
    }
    let myRect = {
      top: pos1.top,
      right: pos1.left + w,
      bottom: pos1.top + h,
      left: pos1.left
    }
    if (txt.startsWith('adv_')) {
      // console.dir(myRect)
    }
    /*
   * 向上查9级，如果父元素是溢出隐藏的，则只显示在父元素中可见的部分
   */
    let pNode = ele.parentNode
    for (i = 0; i < 9 && pNode && pNode.tagName !== 'BODY'; i++) {
      if (pNode.currentStyle.overflow === 'hidden') {
        // console.log(pNode)
        let pDim = Node.getSize(pNode)
        let pPos = $(pNode).offset()
        let pRect = {
          top: pPos.top,
          right: pPos.left + pDim.width,
          bottom: pPos.top + pDim.height,
          left: pPos.left
        }

        myRect = Util.rectIntersect(pRect, myRect)
        if (!myRect) {
          // 如果没有交集就退出
          return
        }
        break
      }
      pNode = pNode.parentNode
    }
    let box = document.createElement('div')
    commentNode._boxNode = box
    box.className = 'z-edit-add-box'
    box.style.position = 'absolute'
    box.style.width = myRect.right - myRect.left + 'px'
    box.style.height = myRect.bottom - myRect.top + 'px'
    let l = isVisible ? myRect.left : '-999'
    let t = isVisible ? myRect.top : '-999'
    box._ofEl = ele
    box._offsetLeft = l - pos0.left
    box._offsetTop = t - pos0.top
    box.style.left = l + 'px'
    box.style.top = t + 'px'

    if (String(lastModifiedTags[indexes]) === '1') {
      box.className = 'z-edit-add-box-changed'
      modifiedTags[indexes] = editorJs.parseAttr(attr)
    }
    fragForIndicators.appendChild(box)

    let button = document.createElement('div')
    commentNode._buttonNode = button
    button.className = 'z-edit-add-button'
    button.style.position = 'absolute'
    button.style.height = '16px'
    button.innerText = '<' + prefix + ':' + name + '>'
    // box.onmouseover = button.onmouseover => {
    //   $(box).addClass('z-edit-add-box-hover');
    // };
    // box.onmouseout = button.onmouseout = () {
    //   $(box).removeClass('z-edit-add-box-hover');
    // };
    // box.onclick = button.onclick = (evt) {
    //   editTag(prefix, name, indexes, attr, box);
    // };
    fragForIndicators.appendChild(button)
    indicatorArr.push(box)
    indicatorArr.push(button)
  },
  setIndicatorPosition () {
    for (let i = 0; i < commentArr.length; i++) {
      let node = commentArr[i]
      let txt = node.nodeValue
      if (!txt.startsWith('_TAGSTART_')) {
        continue
      }
      let box = node._boxNode
      let button = node._buttonNode
      if (!button) {
        // alert(node.nodeValue);
      } else {
        button.style.left = parseInt(box.style.left, 10) + parseInt(box.style.width, 10) / 2 - button.offsetWidth / 2 + 'px'
        button.style.top = parseInt(box.style.top, 10) + parseInt(box.style.height, 10) / 2 - button.offsetHeight / 2 + 'px'
      }
    }
  },

  _DialogSize: {
    Imageplayer: [450, 100],
    Adv: [450, 100],
    Vote: [450, 100],
    Link: [450, 100],
    Include: [450, 100],
    Hotmessage: [450, 100],
    Messagelist: [450, 100],
    File: [450, 250],
    Library: [450, 250],
    Audio: [450, 250],
    Video: [450, 250],
    Imagegroup: [450, 250],
    CustomForm: [450, 300],
    Catalog: [500, 200],
    Article: [550, 320],
    Block: [350, 200],
    Html: [800, 250]
  },

  editTag (prefix, name, indexes, attr, box) {
    prefix = prefix.substring(0, 1).toUpperCase() + prefix.substring(1).toLowerCase()
    name = name.substring(0, 1).toUpperCase() + name.substring(1).toLowerCase()

    let url = TagURLMap[prefix.toLowerCase() + ':' + name.toLowerCase()] + '?EditMode=' + EditMode
    if (!url) {
      Dialog.alert('Error:Not edit enabled tag!')
      return
    }
    url = (window.CONTEXTPATH || '/') + url
    let dlg = new Dialog(
      '编辑标签&lt;' + prefix.toLowerCase() + ':' + name.toLowerCase() + '&gt;',
      url,
      editorJs._DialogSize[name] ? editorJs._DialogSize[name][0] : 500,
      editorJs._DialogSize[name] ? editorJs._DialogSize[name][1] : 200
    )
    if (modifiedTags[indexes]) {
      dlg.Attributes = modifiedTags[indexes]
    } else {
      dlg.Attributes = editorJs.parseAttr(attr)
    }
    dlg.TagIndexes = indexes
    dlg.onOk = () => {
      if (!$DW.UpdateAttributeOnly) {
        let map = $DW.getAttributes()
        let map2 = editorJs.parseAttr(attr)
        let flag = false // 是否有修改
        for (let prop in map) {
          let v = map[prop]
          if (v !== map2[prop]) {
            let o = map2[prop]
            if (v === '' && (o === '' || typeof o === 'undefined')) {
              continue
            }
            $(box).removeClass('z-edit-add-box-hover')
            $(box).addClass('z-edit-add-box-changed')
            modifiedTags[indexes] = map
            flag = true
            break
          }
        }
        if (!flag) {
          modifiedTags[indexes] = null
          $(box).removeClass('z-edit-add-box-changed')
        }
        if (EditMode === 'Pages') {
          if ($DW.save) {
            // $DW.save((){
            // $D.close();
            window.location.reload()
            // });
          } else {
            // window.location.reload();
            // $D.close();
          }
        } else {
          $D.close()
        }
        /* 己下代码已经无法执行
      if ($DW.NeedUpdateHTML) {
        Server.sendRequest("TemplateVisualEditor.getAfterEditHTML", dc, (response) {
          replaceHTML(prefix, name, indexes, response.HTML);
        });
      } */
      } else {
        $D.close()
      }
    }
    dlg.show()
  },

  replaceHTML (prefix, name, indexes, html) {
    for (let i = 0; i < commentArr.length; i++) {
      let start = commentArr[i]
      let txt = start.nodeValue
      let suffix = prefix.toLowerCase() + '_' + name.toLowerCase() + '_' + indexes
      if (!txt.startsWith('_TAGSTART_' + suffix)) {
        continue
      }
      let next = start.nextSibling
      while (next) {
        if (next.nodeType === 8 && next.nodeValue.startsWith('_TAGEND_' + suffix)) {
          break
        }
        let sibling = next.nextSibling
        next.parentNode.removeChild(next)
        next = sibling
      }
      start.insertAdjacentHTML('after', html)

      break
    }
  },

  parseAttr (attr) {
    let len = attr.length
    let arr = []
    let last = 0
    let i
    for (i = 0; i < len; i++) {
      if (attr.charAt(i) === ';' && i !== 0 && attr.charAt(i - 1) !== '\\') {
        arr.push(attr.substring(last, i))
        last = i + 1
      }
    }
    let map = {}
    for (i = 0; i < arr.length; i++) {
      let str = arr[i]
      let k = str.substring(0, str.indexOf(':'))
      let v = str.substring(str.indexOf(':') + 1)
      v = v.replace('\\;', ';')
      v = v.replace('\\"', '"')
      if (v.endsWith(';')) {
        v = v.substring(0, v.length - 1)
      }
      map[k.toLowerCase()] = v
    }
    return map
  },

  removeIndicator () {
    indicatorArr.forEach(n => {
      n.onclick = null
      n.mouseover = null
      n.mouseout = null
      n.mousedown = null
      n.mouseup = null
      $(n).remove()
    })
    textNodeArr.forEach(n => {
      n.contentEditable = false
    })
  },

  getChanges () {
    let map = modifiedTags
    let dc = new DataCollection()
    let flag = false
    let v
    for (let prop in map) {
      v = map[prop]
      if (!v) {
        continue
      }
      flag = true
      dc.add(prop, v, 'Map')
    }
    let modifiedTexts = []
    for (let i = 0; i < textNodeArr.length; i++) {
      let ele = textNodeArr[i]
      v = ele.innerHTML
      let o = ele.OldInnerHTML
      if (v !== o) {
        flag = true
      }
      modifiedTexts.push(o)
      modifiedTexts.push(v)
    }
    // TODO: 这儿有问题，其一DataCollection在哪儿来？其二TemplateFileName 从哪儿来？
    dc.add('TemplateFileName', window.TemplateFileName)
    if (!flag) {
      return null
    }
    return dc.toJSON()
  }
}

export default editorJs
