<template>
  <div :class="[
    type === 'textarea' ? 'qf-textarea' : 'qf-input',
    size ? 'qf-input-' + size : '',
    {
      'is-disabled': inputDisabled,
      'is-focus' : focused
    }
    ]" @mouseenter="hovering = true" @mouseleave="hovering = false">
    <template v-if="type !== 'textarea'">
      <label class="qf-input-label" :style="labelStyles" v-if="label" v-html="label" :for="inputId"></label>
      <slot name="icon"></slot>
      <div class="input-out-zone">
        <input :id="inputId" :tabindex="tabindex" v-if="type !== 'textarea'" :style="inputStyles" class="qf-input-inner" v-bind="$props" :disabled="inputDisabled"
               :autocomplete="autocomplete" :value="currentValue" ref="input" @input="handleInput" @focus="handleFocus" @blur="handleBlur" @change="handleChange"
               :aria-label="label">
        <div class="input-rewrite-placeholder"
             :class="{'is-clear': currentValue !== '' && currentValue !== null}"
             :placeholder="placeholder"></div>
      </div>

      <qf-font-icon name="ic-ic_clean" v-show="showClear" @click="clear" class="qf-input-clear"></qf-font-icon>
      <slot name="trigger"></slot>
      <div class="qf-input-append" v-if="$slots.append">
        <slot name="append"></slot>
      </div>
    </template>
    <textarea v-else :tabindex="tabindex" class="qf-textarea-inner" :value="currentValue" @input="handleInput" ref="textarea" v-bind="$props"
              :disabled="inputDisabled" :style="textareaStyle" @focus="handleFocus" @blur="handleBlur" @change="handleChange" :aria-label="label">
    </textarea>
  </div>
</template>
<script>
import calcTextareaHeight from '../../util/calcTextareaHeight';
import ObjectUtil from '../../util/object';
import NumberUtil from '../../util/number';
import QfFontIcon from '../../font-icon';

export default {
  name: 'QfInput',
  componentName: 'QfInput',
  components: {
    QfFontIcon
  },
  data() {
    return {
      currentValue: this.value,
      textareaCalcStyle: {},
      hovering: false,
      focused: false,
      inputId: null
    };
  },
  props: {
    value: [String, Number],
    placeholder: String,
    resize: String,
    name: String,
    form: String,
    id: String,
    maxlength: Number,
    minlength: Number,
    readonly: Boolean,
    autofocus: Boolean,
    disabled: Boolean,
    selectOnfocus: {
      type: Boolean,
      default: true
    },
    align: {
      type: String,
      default: 'left'
    },
    type: {
      type: String,
      default: 'text'
    },
    autosize: {
      type: [Boolean, Object],
      default: false
    },
    size: String,
    rows: {
      type: Number,
      default: 2
    },
    autocomplete: {
      type: String,
      default: 'off'
    },
    autocorrect: {
      type: String,
      default: 'off'
    },
    max: {},
    min: {},
    step: {},
    label: String,
    clearable: {
      type: Boolean,
      default: false
    },
    tabindex: String,
    labelWidth: String,
    labelAlign: String,
    scale: Number | String,
    autoFormat: {
      type: Boolean,
      default: true
    },
    regex: String,
    filter: Function
  },
  computed: {
    textareaStyle() {
      return ObjectUtil.apply({}, this.textareaCalcStyle, { resize: this.resize });
    },
    labelStyles() {
      return {
        width: this.labelWidth,
        textAlign: this.labelAlign
      };
    },
    inputStyles() {
      return {
        textAlign: this.align
      };
    },
    inputDisabled() {
      return this.disabled;
    },
    showClear() {
      return this.clearable && this.currentValue !== '' && (this.focused || this.hovering);
    },
    pattern() {
      if (this.regex) {
        if (this.regex instanceof RegExp) {
          return this.regex;
        } else if (typeof this.regex === 'string') {
          return new RegExp(this.regex);
        }
      } else if (this.scale !== undefined) {
        return new RegExp('^(\\-|\\+)?\\d*\\.?\\d{0,' + this.scale + '}$');
      }
      return null;
    }
  },
  watch: {
    'value'(val, oldValue) {
      if (this.focused) {
        this.setCurrentValue(val);
      } else {
        this.formatValue(val);
      }
    }
  },
  methods: {
    focus(caret) {
      let input = this.getInput();
      if (input) {
        input.focus();
        if (caret) {
          this.setSelectionStart(caret.start);
          this.setSelectionEnd(caret.end);
        } else if (!this.selectOnfocus) {
          this.moveToEnd(input);
        }
      }
    },
    handleBlur(event) {
      this.formatValue(this.currentValue);
      this.focused = false;
      this.$emit('blur', event);
      // currentValue 可能为 数字，则没有replace,但是这里是为了去除string的空格
      if (this.currentValue && this.currentValue.replace && this.currentValue !== this.currentValue.replace(/(^\s*)|(\s*$)/g, '')) {
        this.currentValue = this.currentValue.replace(/(^\s*)|(\s*$)/g, '');
        this.$emit('input', this.currentValue);
      }
    },
    formatValue(value) {
      if (this.scale !== undefined && this.autoFormat) {
        if (NumberUtil.isNumber(value)) {
          let num = parseFloat(value);
          this.setCurrentValue(num.toFixed(this.scale));
        } else {
          this.setCurrentValue('');
          this.$emit('input', '');
        }
      } else {
        this.setCurrentValue(value);
      }
    },
    inputSelect() {
      let input = this.getInput();
      if (input) {
        input.select();
      }
    },
    getInput() {
      return this.$refs.input || this.$refs.textarea;
    },
    resizeTextarea() {
      const { autosize, type } = this;
      if (type !== 'textarea') return;
      if (!autosize) {
        this.textareaCalcStyle = {
          minHeight: calcTextareaHeight(this.$refs.textarea).minHeight
        };
        return;
      }
      const minRows = autosize.minRows;
      const maxRows = autosize.maxRows;
      this.textareaCalcStyle = calcTextareaHeight(this.$refs.textarea, minRows, maxRows);
    },
    handleFocus(event) {
      this.focused = true;
      this.$emit('focus', event);
      if (this.selectOnfocus) {
        this.inputSelect();
      }
    },
    moveToEnd(el) {
      if (typeof el.selectionStart === 'number') {
        el.selectionStart = el.selectionEnd = el.value.length;
      } else if (typeof el.createTextRange !== 'undefined') {
        var range = el.createTextRange();
        range.collapse(false);
        range.select();
      }
    },
    handleInput(event) {
      this.doInput(event.target.value);
    },
    doInput(value) {
      var valid = !value || !this.pattern || (this.pattern && this.pattern.test(value));
      if (valid && this.filter && !this.filter(value)) {
        valid = false;
      }
      if (!valid) {
        value = this.currentValue || '';
      }
      this.$emit('input', value);
      this.setCurrentValue(value);
      // input.value 和 currentValue不同步
      if (this.getInput() && this.getInput().value !== value) {
        this.getInput().value = value;
      }
      return valid;
    },
    handleChange(event) {
      this.$emit('change', event.target.value);
    },
    setCurrentValue(value) {
      if (value === this.currentValue) return;
      this.$nextTick(_ => {
        this.resizeTextarea();
      });
      this.currentValue = value;
    },
    clear() {
      this.$emit('input', '');
      this.$emit('change', '');
      this.$emit('clear');
      this.setCurrentValue('');
      this.focus();
    },
    getSelectionStart() {
      return this.getInput().selectionStart;
    },
    setSelectionStart(val) {
      this.getInput().selectionStart = val;
    },
    getSelectionEnd() {
      return this.getInput().selectionEnd;
    },
    setSelectionEnd(val) {
      this.getInput().selectionEnd = val;
    }
  },
  created() {
    this.$on('inputSelect', this.inputSelect);
  },
  mounted() {
    this.inputId = Math.random().toString(36).substring(3, 8);
    this.resizeTextarea();
    this.formatValue(this.currentValue);

    if (this.type === 'number') {
      console.log('禁止使用number类型，请优先考虑text+scale或text+regex实现数字录入');
    }
  }
};
</script>
