<script>
import ajax from './ajax';
import UploadDragger from './upload-dragger.vue';

export default {
  inject: ['uploader', 'commonConfig'],
  components: {
    UploadDragger
  },
  props: {
    type: String,
    action: {
      type: String,
      required: true
    },
    name: {
      type: String,
      default: 'file'
    },
    data: Object,
    headers: Object,
    withCredentials: Boolean,
    multiple: Boolean,
    cut: Boolean,
    accept: String,
    onStart: Function,
    onProgress: Function,
    onSuccess: Function,
    onError: Function,
    beforeUpload: Function,
    drag: Boolean,
    onPreview: {
      type: Function,
      default: function() {}
    },
    onRemove: {
      type: Function,
      default: function() {}
    },
    fileList: Array,
    autoUpload: Boolean,
    listType: String,
    httpRequest: {
      type: Function,
      default: ajax
    },
    disabled: Boolean,
    limit: Number,
    onExceed: Function
  },

  data() {
    return {
      mouseover: false,
      reqs: {},
      errorFiles:{},
      prevFile: null,
      prevIndex: -1
    };
  },
  async created() {
    await this.$nextTick()
    this.uploader.$on('retryUpload', (file) => {
      // 重新上次
      this.upload(this.errorFiles[file.name])
    })
    this.uploader.$on('clickInput', (file) => {
      // 再次上传
      if (!this.disabled) {
        this.prevFile = file;
        if (this.$refs.input) {
          this.$refs.input.value = null;
          this.$refs.input.click();
        }
      }
    })
  },
  methods: {
    isImage(str) {
      return str.indexOf('image') !== -1;
    },
    handleChange(ev) {
      if (this.cut) {
        let cut = this.$slots.default[0].context.$children[0].$children[0].$children[1].$children[1]
        cut.getData(ev)
        return false
      }
      const files = ev.target.files;

      if (!files) return;
      this.uploadFiles(files);
    },
    uploadFiles(files) {
      // 如果prevFile存在，那么要替换之前的file，所以要减去1
      if (this.limit && this.fileList.length + files.length - (this.prevFile ? 1 : 0) > this.limit) {
        this.onExceed && this.onExceed(files, this.fileList);
        return;
      }

      let postFiles = Array.prototype.slice.call(files);
      if (!this.multiple) {
        postFiles = postFiles.slice(0, 1); 
      }

      if (postFiles.length === 0) {
        return;
      }

      this.prevIndex = this.prevFile ? this.fileList.findIndex(x => x.uid === this.prevFile.uid) : -1;
      if (this.prevIndex > -1) {
        this.fileList.splice(this.prevIndex, 1);
      }
      postFiles.forEach((rawFile, index) => {
        this.onStart(rawFile, this.prevIndex + index, this.prevIndex === -1);
        if (this.autoUpload) {
          this.upload(rawFile);
        }
      });
    },
    upload(rawFile) {
      if (this.$refs.input) {
        // #108684 limit为1时，点击按钮才上传的话，会没有input
        this.$refs.input.value = null;
      }
      if (!this.beforeUpload) {
        return this.post(rawFile);
      }

      const before = this.beforeUpload(rawFile);
      if (before && before.then) {
        before.then(processedFile => {
          const fileType = Object.prototype.toString.call(processedFile);

          if (fileType === '[object File]' || fileType === '[object Blob]') {
            if (fileType === '[object Blob]') {
              processedFile = new File([processedFile], rawFile.name, {
                type: rawFile.type
              });
            }
            for (const p in rawFile) {
              if (rawFile.hasOwnProperty(p)) {
                processedFile[p] = rawFile[p];
              }
            }
            this.post(processedFile);
          } else {
            this.post(rawFile);
          }
        }, () => {
          this.onRemove(null, rawFile);
        });
      } else if (before !== false) {
        this.post(rawFile);
      } else {
        this.onRemove(null, rawFile);
      }
    },
    abort(file) {
      const { reqs } = this;
      if (file) {
        let uid = file;
        if (file.uid) uid = file.uid;
        if (reqs[uid]) {
          reqs[uid].abort();
        }
      } else {
        Object.keys(reqs).forEach((uid) => {
          if (reqs[uid]) reqs[uid].abort();
          delete reqs[uid];
        });
      }
    },
    post(rawFile) {
      const { uid } = rawFile;
      const options = {
        headers: this.headers,
        withCredentials: this.withCredentials,
        file: rawFile,
        data: this.commonConfig && this.commonConfig.uploadData ? Object.assign({}, this.commonConfig.uploadData, this.data) : this.data,
        filename: this.name,
        action: this.action,
        onProgress: e => {
          this.onProgress(e, rawFile);
        },
        onSuccess: res => {
          this.onSuccess(res, rawFile, this.prevFile, this.prevIndex);
          delete this.reqs[uid];
        },
        onError: err => {
          this.onError(err, rawFile);
          this.errorFiles[rawFile.name] = rawFile
          this.prevFile = null;
          this.prevIndex = -1;
          delete this.reqs[uid];
        }
      };
      const req = this.httpRequest(options);
      this.reqs[uid] = req;
      if (req && req.then) {
        req.then(options.onSuccess, options.onError);
      }
    },
    handleClick() {
      if (!this.disabled) {
        this.prevFile = null;
        this.prevIndex = -1;
        if (this.$refs.input) {
          this.$refs.input.value = null;
          this.$refs.input.click();
        }
        setTimeout(() => {
          document.activeElement && document.activeElement.blur()
        }, 100);
      }
    },
    handleKeydown(e) {
      if (e.target !== e.currentTarget) return;
      if (e.keyCode === 13 || e.keyCode === 32) {
        this.handleClick();
      }
    }
  },
  destroyed() {
     this.uploader.$off('retryUpload')
     this.uploader.$off('clickInput')
  },
  render(h) {
    let {
      handleClick,
      drag,
      name,
      handleChange,
      multiple,
      accept,
      listType,
      uploadFiles,
      disabled,
      handleKeydown,
      limit,
      fileList
    } = this;
    const data = {
      class: {
        'el-upload': true
      },
      on: {
        'click': handleClick,
        keydown: handleKeydown
      }
    };
    data.class[`el-upload--${listType}`] = true;

    // 拖动或者上传数量达到上限时，隐藏上传按钮块
    const showUpload = drag || fileList.length !== limit

    return showUpload ? (
      <div>
        <div {...data} tabindex="0">
          {
            drag
              ? <upload-dragger disabled={disabled} on-file={uploadFiles}>{this.$slots.default}</upload-dragger>
              : fileList.length === limit ? '' :
              this.$slots.default
          }
          <input onClick={(event) => event.stopPropagation()} class="el-upload__input" type="file" ref="input" name={name} on-change={handleChange} multiple={multiple} accept={accept}></input>
        </div>
        { this.$slots.tip }
      </div>
    ) : 
    <input onClick={(event) => event.stopPropagation()} class="el-upload__input" type="file" ref="input" name={name} on-change={handleChange} multiple={multiple} accept={accept}></input>;
  }
};
</script>
