text: /**
   * Create by capricorncd
   * 2018/5/16 0016.
   * https://github.com/capricorncd
   */
  import '../style/image-preview.styl'
  import util from './util'
  import dom from './dom'
  import ic from './img-controls'
  import keyboard from './keyboard'
  import broadcast from './broadcast'
  import {
    mouseWheel,
    filterOptions,
    fmtImageArray,
    appendIconfontToHead,
    createToolbarButtons
  } from './fn'
  
  // window.util = util
  
  // 默认配置参数
  const __DEFAULT = {
    // 背景遮罩透明度[0-1]
    // backgroundOpacity: .6,
    // 分页mouseover切换图片
    paginationable: true,
    // 显示关闭按钮
    showClose: true,
    // 显示上一张/下一张箭头
    showSwitchArrow: true,
    // 显示工具栏
    showToolbar: false,
    // 显示分页导航栏
    showPagination: true,
    // 缩放
    scalable: true,
    // 旋转
    rotatable: true,
    // 移动
    movable: true,
    // 按键配置
    keyboard: {
      prev: 'left',
      next: 'right',
      // 滚动鼠标[放大，缩小]
      scale: 'mousewheel',
      // [Clockwise 顺时针, anticlockwise 逆时针]
      rotate: ['up', 'down'],
      close: 'escape'
    },
    // 图标字体
    iconfont: '//at.alicdn.com/t/font_613889_qd2ugx65fxadzpvi.css',
    // 工具栏按钮数量及顺序配置
    toolbarButtons: ['prev', 'enlarge', 'rotate', 'reduce', 'next'],
    // mask background, default: 'rgba(0, 0, 0, .6)'
    maskBackground: null
  }
  
  // const log = console.log
  
  const Z_INDEX = 10
  
  class ZxImageViewer {
    constructor (opts, arr) {
      if (typeof arr === 'undefined' && util.isArray(opts)) {
        arr = opts
        opts = undefined
      }
      // 初始化参数
      let options = util.isObject(opts) ? util.assign(__DEFAULT, opts) : __DEFAULT
      // broadcast
      this.broadcast = broadcast.broadcast
      // 判断键名配置是否有重复的
      this.opts = filterOptions(options)
      // 图片数组
      this.images = []
      this._init()
      if (util.isArray(arr)) {
        this.init(arr, 0)
      }
    }
  
    // 内部初始化
    _init () {
      const opts = this.opts
      // log(opts)
      // 预览容器dom结构对象
      const vnode = {
        tag: 'div',
        attrs: {
          class: 'zx-image-preview-wrapper',
          style: 'display:none;' + (opts.maskBackground ? `background:${opts.maskBackground}` : '')
        },
        child: [
          // 预览图片
          {
            tag: 'img',
            attrs: {
              class: 'zip-picture v-transition'
            }
          }
        ]
      }
      // 显示左右箭头
      if (opts.showSwitchArrow) {
        // 左右方向箭头
        vnode.child.push({tag: 'div', attrs: {class: 'zip-arrow _prev-arrow'}})
        vnode.child.push({tag: 'div', attrs: {class: 'zip-arrow _next-arrow'}})
      }
      // 显示关闭按钮
      if(opts.showClose) {
        vnode.child.push({tag: 'div', attrs: {class: 'zip-close _cur'}})
      }
      // 工具栏
      if (opts.showToolbar) {
  
        vnode.child.push({
          tag: 'div',
          attrs: {
            class: 'zip-tool-wrapper'
          }
          // child: createToolbarButtons(opts.toolbarButtons)
        })
      }
      // 分页栏
      if (opts.showPagination) {
        vnode.child.push({tag: 'div', attrs: {class: 'zip-pagination-wrapper'}})
      }
  
      // 创建dom结构
      // 预览容器
      this.$container = dom.create(vnode)
      // 关闭按钮
      this.$close = dom.query('.zip-close', this.$container)
      // 预览图片
      this.$img = dom.query('.zip-picture', this.$container)
      // 工具栏
      this.$tool = dom.query('.zip-tool-wrapper', this.$container)
      // 分页栏
      this.$pagination = dom.query('.zip-pagination-wrapper', this.$container)
  
      // 背景透明度
      // if (typeof opts.backgroundOpacity !== 'undefined') {
      //   const bo = util.toNumber(opts.backgroundOpacity)
      //   this.$container.style.background = `rgba(0, 0, 0, ${bo})`
      // }
  
      // preview是否显示
      this.isPreview = false
      // 是否添加到body
      this.isAppendToBody = dom.appendToBody(this.$container)
      this.index = 0
      // 事件处理器
      this._eventHandler()
      // 添加图标字体样式至head
      appendIconfontToHead(dom, opts.iconfont)
    }
  
    // 初始化
    init (images, index) {
      if (!this.isAppendToBody) {
        this.isAppendToBody = dom.appendToBody(this.$container)
      }
      // 初始化数据
      let imgArray = fmtImageArray(images)
      if (imgArray) {
        this.images = imgArray
      }
      if (typeof index !== 'undefined') {
        this.index = index >= this.images.length ? 0 : util.int(index)
      }
      this._updateToolbar()
      this._resetPaginationInnerHtml()
      this._resetCurrent$img()
    }
  
    /**
     * 更新当前图片数组
     * @param images
     */
    update (images) {
      this.init(images, 0)
    }
  
    // 重置分页html结构
    _resetPaginationInnerHtml () {
      if (!this.$pagination) return
      let html = ''
      let len = this.images.length
      this.images.forEach((item, index) => {
        html += `<i style="width:${Math.floor(1 / len * 100)}%" data-index="${index}" class="_item${this.index === index ? ' _item-active' : ''}"></i>`
      })
      this.$pagination.innerHTML = html
      this._checkArrowPrevNext()
    }
  
    /**
     * 查看图片
     * @param index 当前图片在数组中的索引
     * @param angle 旋转角度
     * @param images 图片数组
     */
    view (index = 0, angle, images) {
      // 参数验证
      if (typeof angle !== 'undefined') {
        if (util.isArray(angle) && typeof images === 'undefined') {
          images = angle
          angle = null
        }
      }
      let imgArray = fmtImageArray(images)
      if (imgArray) {
        this.images = imgArray
        this._resetPaginationInnerHtml()
        this._updateToolbar()
      }
      // 图片数组是否有元素判断
      if (this.images.length === 0) {
        throw new Error(`图片数组images参数为空或格式不正确!`)
      }
      if (index < this.images.length) {
        this.index = util.int(index)
      }
      this._resetCurrent$img(angle)
      this.show()
      // 修改Pagination样式
      this._changePaginationClass()
    }
  
    // 销毁对象
    destroy () {
      try {
        this.$container.parentNode.removeChild(this.$container)
        this.$container = null
      } catch (e) {}
    }
  
    /**
     * 重置当前被预览的图片
     * @param _angle 设置旋转角度
     * @private
     */
    _resetCurrent$img (_angle) {
      let item = this.images[this.index]
      const _this = this
      const $img = this.$img
      $img.src = item.url
      // 获取设置的图片旋转角度
      let angle = util.int(_angle || item.angle)
      // 根据缩略图设置的旋转角度，重置预览图片的旋转角度
      dom.attr($img, 'rotate-angle', angle)
      $img.onload = function () {
        // 旋转和计算$img位置
        ic.rotate($img, angle)
        // 移除on-error样式
        dom.rmClass(_this.$container, 'on-error')
      }
      $img.onerror = function () {
        // 添加on-error样式
        dom.addClass(_this.$container, 'on-error')
      }
    }
  
    /**
     * 事件处理
     * @private
     */
    _eventHandler () {
      // 禁止图片被选中
      this.$container.addEventListener('selectstart', e => {
        e.preventDefault()
      })
      // document.onselectstart = new Function('event.returnValue=false')
      // 关闭
      this.$close && this.$close.addEventListener('click', e => {
        e.stopPropagation()
        this.hide()
      })
  
      // 点击图片
      this.$img.addEventListener('click', e => {
        e.stopPropagation()
      })
  
      // 拖动图片
      if (this.opts.movable) {
        ic.move(this.$img)
      } else {
        this.$img.style.cursor = 'auto'
      }
  
      // 点击preview容器
      this.$container.addEventListener('click', e => {
        const $el = e.target
        if (dom.hasClass($el, '_prev-arrow')) {
          this.prev()
        } else if (dom.hasClass($el, '_next-arrow')) {
          this.next()
        } else {
          this.hide()
        }
      })
  
      // 工具栏点击事件
      this.$tool && this.$tool.addEventListener('click', e => {
        e.stopPropagation()
        const $el = e.target
        // console.log($el.className)
        // let isToolItem = dom.hasClass($el, 'zx')
        // if (!isToolItem) return
        // 上一张
        if (dom.hasClass($el, 'zx-prev')) {
          this.prev()
        }
        // 下一张
        else if (dom.hasClass($el, 'zx-next')) {
          this.next()
        }
        // 放大
        else if (dom.hasClass($el, 'zx-enlarge')) {
          this._scale(1)
        }
        // 缩小
        else if (dom.hasClass($el, 'zx-reduce')) {
          this._scale(-1)
        }
        // 旋转
        else if (dom.hasClass($el, 'zx-rotate')) {
          this._rotate()
        }
      }, true)
  
      // 点击统计栏
      this.$pagination && this.opts.paginationable && this.$pagination.addEventListener('mouseover', e => {
        // 处理事件
        this._handleChangePage(e)
      })
  
      // 点击统计栏，阻止事件冒泡
      this.$pagination && this.$pagination.addEventListener('click', e => {
        e.stopPropagation()
      })
  
      const keys = this.opts.keyboard || {}
      // 键盘事件
      window.addEventListener('keyup', e => {
        if (!this.isPreview) return
        let keyCode = e.keyCode
        // log(keyCode, e.key, e.code, e.which)
        // 阻止方向键移动元素或滚动条
        e.preventDefault()
  
        // 上一张
        if (keyboard.code(keys.prev) === keyCode) {
          this.prev()
        }
        // 下一张
        if (keyboard.code(keys.next) === keyCode) {
          this.next()
        }
        // 旋转
        if (util.isArray(keys.rotate)) {
          // 顺时针
          if (keyboard.code(keys.rotate[0]) === keyCode) {
            this._rotate()
          }
          // 逆时针
          if (keyboard.code(keys.rotate[1]) === keyCode) {
            this._rotate(true)
          }
        } else if (typeof keys.rotate === 'string' && keyboard.code(keys.rotate) === keyCode) {
          // 顺时针
          this._rotate()
        }
        // 缩放
        if (util.isArray(keys.scale)) {
          // 放大
          if (keyboard.code(keys.scale[0]) === keyCode) {
            this._scale(1)
          }
          // 缩小
          if (keyboard.code(keys.scale[1]) === keyCode) {
            this._scale(-1)
          }
        } else if (typeof keys.scale === 'string' && keyboard.code(keys.scale) === keyCode) {
          this._scale(1)
        }
  
        // 关闭
        if (keyboard.code(keys.close) === keyCode) {
          this.hide()
        }
      })
  
      // log(this.opts)
      // 滚动鼠标前进后退
      if (util.toLower(keys.prev) === 'mousewheel') {
        mouseWheel(switchWheelHandler)
      }
  
      // 滚动鼠标缩放
      if (util.toLower(keys.scale) === 'mousewheel') {
        mouseWheel(scaleWheelHandler)
      }
  
      // 滚动鼠标旋转
      if (util.toLower(keys.rotate) === 'mousewheel') {
        mouseWheel(rotateWheelHandler)
      }
  
      const _this = this
      // 滚动鼠标缩放处理
      function scaleWheelHandler (e) {
        if (!_this.isPreview) return
        // log(e)
        const $el = e.target
        if ($el !== _this.$img) return
        // 浏览器兼容处理
        // 鼠标滚动方向
        let wheelDelta = e.wheelDelta || -e.detail
        _this._scale(wheelDelta)
      }
      // 滚动鼠标前后切换处理
      function switchWheelHandler (e) {
        if (!_this.isPreview) return
        let wheelDelta = e.wheelDelta || -e.detail
        wheelDelta > 0 ? _this.prev() : _this.next()
      }
      // 滚动鼠标旋转处理
      function rotateWheelHandler (e) {
        if (!_this.isPreview) return
        let wheelDelta = e.wheelDelta || -e.detail
        _this._rotate(wheelDelta > 0)
      }
    }
  
    // 点击或鼠标滑过统计栏处理
    _handleChangePage (e) {
      if (this.images.length <= 1) return
      // e.stopPropagation()
      const $el = e.target
      let isToolItem = dom.hasClass($el, '_item')
      if (!isToolItem) return
      let index = dom.attr($el, 'data-index') >>> 0
      // 当前点击index和this.index相同
      if (this.index === index) return
      this.index = index
      this._changePaginationClass($el)
      this._resetCurrent$img()
    }
  
    // 修改统计栏item样式
    _changePaginationClass ($el) {
      if (!this.$pagination) return
      $el = $el || this.$pagination.querySelectorAll('._item')[this.index]
      const $active = dom.query('._item-active', this.$pagination)
      dom.rmClass($active, '_item-active')
      dom.addClass($el, '_item-active')
    }
  
    // 隐藏图片预览
    hide () {
      if (this.$container) {
        broadcast.emit('close')
        this.$container.style.display = 'none'
        this.isPreview = false
      }
    }
  
    // 显示图片预览
    show () {
      if (this.$container) {
        let zIndex = util.getMaxZindex()
        if (zIndex > Z_INDEX) {
          this.$container.style.zIndex = zIndex
        }
        broadcast.emit('show')
        this.$container.style.display = 'block'
        this.isPreview = true
      }
    }
  
    // 上一张
    prev () {
      this._switchImage('prev')
    }
  
    // 下一张
    next () {
      this._switchImage('next')
    }
  
    /**
     * 旋转
     * @param isAnticlockwise 是否逆时针
     */
    _rotate (isAnticlockwise) {
      // 禁止旋转
      if (!this.opts.rotatable) return
      let deg = isAnticlockwise ? -90 : 90
      const angle = util.int(dom.attr(this.$img, 'rotate-angle')) + deg
      dom.attr(this.$img, 'rotate-angle', angle)
      ic.rotate(this.$img, angle)
    }
  
    /**
     * 缩放
     * @private
     */
    _scale (wheelDelta) {
      // 禁止缩放
      if (!this.opts.scalable) return
      ic.scale(this.$img, wheelDelta)
    }
  
    // 切换
    _switchImage (type) {
      let maxIndex = this.images.length - 1
      if (maxIndex <= 0) return
      switch (type) {
        case 'prev':
          if (+this.index === 0) {
            this.index = maxIndex
          } else {
            this.index--
          }
          break
        case 'next':
          if (+this.index >= maxIndex) {
            this.index = 0
          } else {
            this.index++
          }
          break
      }
      let item = this.images[this.index]
      this.$img.src = item.url
      const angle = util.int(item.angle)
      // 根据缩略图设置的旋转角度，重置预览图片的旋转角度
      dom.attr(this.$img, 'rotate-angle', angle)
      ic.rotate(this.$img, angle)
      this._changePaginationClass()
    }
  
    // 验证图片切换键是否显示
    _checkArrowPrevNext () {
      // 不显示左右箭头
      if (!this.opts.showSwitchArrow) return
      // 图片数组只有一张或为空
      if (this.images.length <= 1) {
        this.togglePrev('hide')
        this.toggleNext('hide')
      }
    }
  
    togglePrev (type) {
      const $el = dom.query('._prev-arrow', this.$container)
      if ($el) $el.style.display = type === 'show' ? 'block' : 'none'
    }
  
    toggleNext (type) {
      const $el = dom.query('._next-arrow', this.$container)
      if ($el) $el.style.display = type === 'show' ? 'block' : 'none'
    }
  
    /**
     * 更新工具栏按钮
     * 当一张图片时，隐藏左右按钮
     * 2019-06-21
     * @private
     */
    _updateToolbar () {
      if (!this.$tool) return
      let buttons = this.images.length <= 1
        ? this.opts.toolbarButtons.filter(item => item !== 'prev' && item !== 'next')
        : this.opts.toolbarButtons
  
      let vnode = {
        tag: 'div',
        child: createToolbarButtons(buttons)
      }
      this.$tool.innerHTML = dom.getInnerHtml(vnode)
    }
  }
  
  ZxImageViewer.prototype.on = broadcast.on
  ZxImageViewer.prototype.off = broadcast.off
  ZxImageViewer.prototype.emit = broadcast.emit
  
  export { ZxImageViewer }
  
  export default ZxImageViewer
  