/**
 * @fileoverview editable 插件
 */
const config = require('./config')
const Parser = require('../parser')
function Editable (vm) {
  this.vm = vm
  this.editHistory = [] // 历史记录
  this.editI = -1 // 历史记录指针
  vm._mask = [] // 蒙版被点击时进行的操作
  vm._setData = function (path, val) {
    const paths = path.split('.')
    let target = vm
    for (let i = 0; i < paths.length - 1; i++) {
      target = target[paths[i]]
    }
    vm.$set(target, paths.pop(), val)
  }
  /**
   * @description 移动历史记录指针
   * @param {Number} num 移动距离
   */
  const move = num => {
    setTimeout(() => {
      const item = this.editHistory[this.editI + num]
      if (item) {
        this.editI += num
        vm._setData(item.key, item.value)
      }
    }, 200)
  }
  vm.undo = () => move(-1) // 撤销
  vm.redo = () => move(1) // 重做
  /**
   * @description 更新记录
   * @param {String} path 更新内容路径
   * @param {*} oldVal 旧值
   * @param {*} newVal 新值
   * @param {Boolean} set 是否更新到视图
   * @private
   */
  vm._editVal = (path, oldVal, newVal, set) => {
    // 当前指针后的内容去除
    while (this.editI < this.editHistory.length - 1) {
      this.editHistory.pop()
    }
    // 最多存储 30 条操作记录
    while (this.editHistory.length > 30) {
      this.editHistory.pop()
      this.editI--
    }
    const last = this.editHistory[this.editHistory.length - 1]
    if (!last || last.key !== path) {
      if (last) {
        // 去掉上一次的新值
        this.editHistory.pop()
        this.editI--
      }
      // 存入这一次的旧值
      this.editHistory.push({
        key: path,
        value: oldVal
      })
      this.editI++
    }
    // 存入本次的新值
    this.editHistory.push({
      key: path,
      value: newVal
    })
    this.editI++
    // 更新到视图
    if (set) {
      vm._setData(path, newVal)
    }
  }
  /**
   * @description 获取菜单项
   * @private
   */
  vm._getItem = function (node, up, down) {
    let items
    let i
    if (node === 'color') {
      return config.color
    }
    if (node.name === 'img') {
      items = config.img.slice(0)
      if (!vm.getSrc) {
        i = items.indexOf('换图')
        if (i !== -1) {
          items.splice(i, 1)
        }
        i = items.indexOf('超链接')
        if (i !== -1) {
          items.splice(i, 1)
        }
        i = items.indexOf('预览图')
        if (i !== -1) {
          items.splice(i, 1)
        }
      }
      i = items.indexOf('禁用预览')
      if (i !== -1 && node.attrs.ignore) {
        items[i] = '启用预览'
      }
    } else if (node.name === 'a') {
      items = config.link.slice(0)
      if (!vm.getSrc) {
        i = items.indexOf('更换链接')
        if (i !== -1) {
          items.splice(i, 1)
        }
      }
    } else if (node.name === 'video' || node.name === 'audio') {
      items = config.media.slice(0)
      i = items.indexOf('封面')
      if (!vm.getSrc && i !== -1) {
        items.splice(i, 1)
      }
      i = items.indexOf('循环')
      if (node.attrs.loop && i !== -1) {
        items[i] = '不循环'
      }
      i = items.indexOf('自动播放')
      if (node.attrs.autoplay && i !== -1) {
        items[i] = '不自动播放'
      }
    } else if (node.name === 'card') {
      items = config.card.slice(0)
    } else {
      items = config.node.slice(0)
    }
    if (!up) {
      i = items.indexOf('上移')
      if (i !== -1) {
        items.splice(i, 1)
      }
    }
    if (!down) {
      i = items.indexOf('下移')
      if (i !== -1) {
        items.splice(i, 1)
      }
    }
    return items
  }
  /**
   * @description 显示 tooltip
   * @param {object} obj
   * @private
   */
  vm._tooltip = function (obj) {
    vm.$set(vm, 'tooltip', {
      top: obj.top,
      items: obj.items
    })
    vm._tooltipcb = obj.success
  }
  /**
   * @description 显示滚动条
   * @param {object} obj
   * @private
   */
  vm._slider = function (obj) {
    vm.$set(vm, 'slider', {
      min: obj.min,
      max: obj.max,
      value: obj.value,
      top: obj.top
    })
    vm._slideringcb = obj.changing
    vm._slidercb = obj.change
  }
  /**
   * @description 显示颜色选择
   * @param {object} obj
   * @private
   */
  vm._color = function (obj) {
    vm.$set(vm, 'color', {
      items: obj.items,
      top: obj.top
    })
    vm._colorcb = obj.success
  }
  /**
   * @description 点击蒙版
   * @private
   */
  vm._maskTap = function () {
    // 隐藏所有悬浮窗
    while (vm._mask.length) {
      (vm._mask.pop())()
    }
    if (vm.tooltip) {
      vm.$set(vm, 'tooltip', null)
    }
    if (vm.slider) {
      vm.$set(vm, 'slider', null)
    }
    if (vm.color) {
      vm.$set(vm, 'color', null)
    }
  }
  /**
   * @description 插入节点
   * @param {Object} node
   */
  function insert (node) {
    if (vm._edit) {
      vm._edit.insert(node)
    } else {
      const nodes = vm.nodes.slice(0)
      nodes.push(node)
      vm._editVal('nodes', vm.nodes, nodes, true)
    }
  }
  /**
   * @description 在光标处插入指定 html 内容
   * @param {String} html 内容
   */
  vm.insertHtml = html => {
    this.inserting = true
    const arr = new Parser(vm).parse(html)
    this.inserting = undefined
    for (let i = 0; i < arr.length; i++) {
      insert(arr[i])
    }
  }
  /**
   * @description 在光标处插入图片
   */
  vm.insertImg = function () {
    vm.getSrc && vm.getSrc('img').then(src => {
      if (typeof src === 'string') {
        src = [src]
      }
      const parser = new Parser(vm)
      for (let i = 0; i < src.length; i++) {
        insert({
          name: 'img',
          attrs: {
            src: parser.getUrl(src[i])
          }
        })
      }
    }).catch(() => { })
  }
  /**
   * @description 在光标处插入一个链接
   */
  vm.insertLink = function () {
    vm.getSrc && vm.getSrc('link').then(url => {
      insert({
        name: 'a',
        attrs: {
          href: url
        },
        children: [{
          type: 'text',
          text: url
        }]
      })
    }).catch(() => { })
  }
  /**
   * @description 在光标处插入一个表格
   * @param {Number} rows 行数
   * @param {Number} cols 列数
   */
  vm.insertTable = function (rows, cols) {
    const table = {
      name: 'table',
      attrs: {
        style: 'display:table;width:100%;margin:10px 0;text-align:center;border-spacing:0;border-collapse:collapse;border:1px solid gray'
      },
      children: []
    }
    for (let i = 0; i < rows; i++) {
      const tr = {
        name: 'tr',
        attrs: {},
        children: []
      }
      for (let j = 0; j < cols; j++) {
        tr.children.push({
          name: 'td',
          attrs: {
            style: 'padding:2px;border:1px solid gray'
          },
          children: [{
            type: 'text',
            text: ''
          }]
        })
      }
      table.children.push(tr)
    }
    insert(table)
  }
  /**
   * @description 插入视频/音频
   * @param {Object} node
   */
  function insertMedia (node) {
    if (typeof node.src === 'string') {
      node.src = [node.src]
    }
    const parser = new Parser(vm)
    // 拼接主域名
    for (let i = 0; i < node.src.length; i++) {
      node.src[i] = parser.getUrl(node.src[i])
    }
    insert({
      name: 'div',
      attrs: {
        style: 'text-align:center'
      },
      children: [node]
    })
  }
  /**
   * @description 在光标处插入一个视频
   */
  vm.insertVideo = function () {
    vm.getSrc && vm.getSrc('video').then(src => {
      insertMedia({
        name: 'video',
        attrs: {
          controls: 'T'
        },
        children: [],
        src,
        // #ifdef APP-PLUS
        html: ``
        // #endif
      })
    }).catch(() => { })
  }
  /**
   * @description 在光标处插入一个音频
   */
  vm.insertAudio = function () {
    vm.getSrc && vm.getSrc('audio').then(attrs => {
      let src
      if (attrs.src) {
        src = attrs.src
        attrs.src = undefined
      } else {
        src = attrs
        attrs = {}
      }
      attrs.controls = 'T'
      insertMedia({
        name: 'audio',
        attrs,
        children: [],
        src
      })
    }).catch(() => { })
  }
  /**
   * @description 在光标处插入一段文本
   */
  vm.insertText = function () {
    insert({
      name: 'p',
      attrs: {},
      children: [{
        type: 'text',
        text: ''
      }]
    })
  }
  /**
   * @description 清空内容
   */
  vm.clear = function () {
    vm._maskTap()
    vm._edit = undefined
    vm.$set(vm, 'nodes', [{
      name: 'p',
      attrs: {},
      children: [{
        type: 'text',
        text: ''
      }]
    }])
  }
  /**
   * @description 获取编辑后的 html
   */
  vm.getContent = function () {
    let html = '';
    // 递归遍历获取
    (function traversal (nodes, table) {
      for (let i = 0; i < nodes.length; i++) {
        let item = nodes[i]
        if (item.type === 'text') {
          html += item.text.replace(/&/g, '&').replace(//g, '>').replace(/\n/g, '
').replace(/\xa0/g, ' ') // 编码实体
        } else {
          if (item.name === 'img') {
            item.attrs.i = ''
            // 还原被转换的 svg
            if ((item.attrs.src || '').includes('data:image/svg+xml;utf8,')) {
              html += item.attrs.src.substr(24).replace(/%23/g, '#').replace('