import { getDocument } from './model'

/**
 * 生成唯一Id，每个节点具有唯一Id.
 */
let _uid = 1
function _uniqueId () {
  return (_uid++).toString()
}

/**
 * VDom节点基类
 */
class DomNode {
  constructor () {
    this.nodeType = DomNode.nodeType.Unknown
    this.ref = _uniqueId()  // 作为在nodeMap中的key值
    this.children = []  // 子节点
    this.layoutChildren = []   // 参与布局的子节点
    this.parentNode = null  // 父节点
    this.nextSibling = null  // 兄弟节点双向链表
    this.previousSibling = null
  }

  /**
   * 支持渲染的父节点（非片段）
   */
  renderParent () {
    let parent = this.parentNode
    while (parent && !parent.supportRender()) {
      parent = parent.parentNode
    }
    return parent
  }

  /**
   * 获取可渲染子节点引用,包括自己（遍历片段）
   */
  renderRef () {
    let refs = []
    if (this.nodeType === DomNode.nodeType.Fragment) {
      this.layoutChildren.forEach(child => {
        refs = refs.concat(child.renderRef())
      })
    }
    else {
      refs.push(this.ref)
    }
    return refs
  }

  /**
   * 支持渲染的节点数目（遍历片段）
   */
  renderCount () {
    let count = this.supportRender() ? 1 : 0
    if (this.nodeType === DomNode.nodeType.Fragment) {
      this.layoutChildren.forEach(child => {
        count += child.renderCount()
      })
    }
    return count
  }

  /**
   * 计算子节点的绘制索引（相对实际渲染父节点）
   * @returns {*}
   */
  renderIndex () {
    // 只有支持布局的节点才有效
    const parent = this.parentNode
    if (!parent || !this.supportLayout()) {
      return this.type === 'document' ? 0 : -1
    }
    // 如果发生，说明数据异常
    const localIndex = parent.renderChildIndex(this)
    // 父节点是非法节点
    let parentIndex = 0
    if (!parent.supportRender()) {
      parentIndex = parent.renderIndex()
    }

    if (localIndex < 0 || parentIndex < 0) {
      return -1
    }

    return localIndex + parentIndex
  }

  /**
   * 计算子节点的相对绘制索引
   * @param child
   * @returns {*}
   */
  renderChildIndex (child) {
    // 只有支持布局的节点才有效
    if (!this.layoutChildren || this.layoutChildren.length <= 0) {
      return -1
    }
    let index = this.layoutChildren.indexOf(child)
    if (index > 0) {
      const num = 0 + index
      index = 0
      for (let i = 0; i < num; i++) {
        index += this.layoutChildren[i].renderCount()
      }
    }
    return index
  }

  /**
   * 删除当前节点，并从nodeMap中移除.
   */
  destroy () {
    // 删除节点在nodeMap的索引
    const doc = getDocument(this.docId)
    if (doc) {
      delete this.docId
      delete doc.nodeMap[this.ref]
    }
    // 递归删除所有孩子节点
    this.children.forEach(child => {
      child.destroy()
    })
  }

  /**
   * 是否支持渲染
   */
  supportRender () {
    return (this.nodeType > DomNode.nodeType.Unknown && this.nodeType < DomNode.nodeType.Fragment)
  }

  /**
   * 是否支持布局
   */
  supportLayout () {
    return (this.nodeType > DomNode.nodeType.Unknown && this.nodeType < DomNode.nodeType.Comment)
  }

  /**
   * 获取当前节点的下一个兄弟节点（非扁平化）
   * @param {object} node
   */
  nextLayoutElement () {
    let node = this.nextSibling
    while (node) {
      if (node.supportLayout()) {
        return node
      }
      node = node.nextSibling
    }
  }

  /**
   * 获取当前节点的上一个兄弟节点（非扁平化）
   * @param {object} node
   */
  prevLayoutElement () {
    let node = this.previousSibling
    while (node) {
      if (node.supportLayout()) {
        return node
      }
      node = node.previousSibling
    }
  }

  /**
   * 获取当前节点的layout索引（非扁平化）
   */
  layoutElementIndex () {
    let node = this.previousSibling
    let index = 0
    while (node) {
      if (node.supportLayout()) {
        index += 1
      }
      node = node.previousSibling
    }
    return index
  }
}

// 保留Id
DomNode.documentId = '-1'
DomNode.rootId = '-2'

/**
 * 节点类型枚举
 */
DomNode.nodeType = {
  Unknown: 0,
  Document: 1,
  Element: 2,
  Fragment: 512,
  Comment: 1024
}

export default DomNode
