<template>
  <span class="uif-upload" :class="classes" @click="handleClick" @paste="handlePaste"
       @dragover.prevent="hover = true" @dragleave.prevent="hover = false" @drop.prevent="onDrop">
    <slot :hover="hover"></slot>
    <input ref="input" type="file" class="uif-upload-input" :multiple="multiple"
           @change="handleChange" :accept="accept">
  </span>
</template>
<script>
import Notice from '@uif/core/lib/prototypes/notice'
import {filter, forEach, toArray} from '@uif/core/lib/utils/array'
import {checkEmpty, checkSize, checkExt} from '@uif/core/lib/utils/modifiers'

export default {
  name: 'u-upload',
  props: {
    multiple: {
      type: Boolean,
      default: false
    },
    paste: {
      type: Boolean,
      default: false
    },
    disabled: {
      type: Boolean,
      default: false
    },
    // input原生属性
    accept: {
      type: String
    },
    // 文件类型检查
    ext: {
      type: Array,
      default () {
        return []
      }
    },
    // 文件大小 ( 兆 )
    size: {
      type: Number,
      default: 50
    },
    // 检查文件方法
    modifiers: {
      type: Array,
      default () {
        return []
      }
    },
    // 检查错误使用Notice警告
    notice: {
      type: Boolean,
      default: true
    }
  },
  data () {
    return {
      hover: false
    }
  },
  computed: {
    classes () {
      return {
        'uif-upload-drag-hover': this.hover
      }
    }
  },
  methods: {
    handleClick () {
      if (this.disabled) return
      this.$refs.input.click()
      this.$emit('focus')
    },
    handleChange (e) {
      const files = e.target.files
      if (!files) return
      this.uploadFiles(files)
      this.$refs.input.value = null
    },
    onDrop (e) {
      this.hover = false
      if (this.disabled) return
      this.uploadFiles(e.dataTransfer.files)
    },
    handlePaste (e) {
      if (this.disabled) return
      if (this.paste) {
        this.uploadFiles(e.clipboardData.files)
      }
    },
    uploadFiles (files) {
      let fileList = toArray(files)
      if (!this.multiple) fileList = [fileList[0]]
      if (fileList.length > 0 && this.checkFiles(fileList)) {
        this.$emit('change', fileList)
      }
      this.$emit('blur')
    },
    // 检查文件列表
    checkFiles (files) {
      const modifiers = this.getModifiers()
      for (let i = 0; i < files.length; i++) {
        const file = files[i]
        for (let j = 0; j < modifiers.length; j++) {
          const {check, message} = modifiers[j]
          if (!check(file)) {
            if (this.notice) {
              Notice.warning(message)
            }
            this.$emit('error', {file, modifier: modifiers[j]})
            return false
          }
        }
      }
      return true
    },
    // 获取检查文件方法
    getModifiers () {
      let modifiers = [checkEmpty(), checkSize(this.size), checkExt(this.ext)]
      forEach(this.modifiers, (modifier) => {
        if (modifier.name) {
          modifiers = filter(modifiers, m => m.name !== modifier.name)
        }
        modifiers.push(modifier)
      })
      return filter(modifiers, value => !value.disabled)
    }
  }
}
</script>
