<template>
    <div :class="wrapClasses">
        <template v-if="type !== 'textarea'">
            <div :class="[prefixCls + '-group-prepend']" v-if="prepend" v-show="slotReady"><slot name="prepend"></slot></div>
            <i class="zz-icon" :class="['zz-icon-ios-close-circle', prefixCls + '-icon', prefixCls + '-icon-clear' , prefixCls + '-icon-normal', difEmpty]" v-if="clearable && currentValue && !$slots.append &&  !disabled" @mousedown.prevent  @click="handleClear"></i>
            <i class="zz-icon" :class="['zz-icon-' + icon, prefixCls + '-icon', prefixCls + '-icon-normal']" v-if="icon && isIconShow" :style="{ fonSize: '16px' }" @click="handleIconClick"></i>
            <i class="zz-icon zz-icon-ios-search" :class="searchIconClasses" v-if="search && enterButton === false" @click="handleIconClick"></i>
            <span class="zz-input-suffix" v-else-if="showSuffix">
                <slot name="suffix"><i class="zz-icon" :class="['zz-icon-' + suffix]" v-if="suffix" @click="handleIconClick"></i>
                </slot>
            </span>
            <input
                :id="elementId"
                :autocomplete="autocomplete"
                :spellcheck="spellcheck"
                ref="input"
                :type="type"
                :class="inputClasses"
                :placeholder="currentPlaceholder"
                :disabled="disabled"
                :maxlength="maxlength"
                :readonly="readonly"
                :name="name"
                :value="currentValue"
                :number="number"
                :autofocus="autofocus"
                @keyup.enter="handleEnter"
                @keyup="handleKeyup"
                @keypress="handleKeypress"
                @keydown="handleKeydown"
                @paste="handlePaste"
                @focus="handleFocus"
                @blur="handleBlur"
                @click="handleClick"
                @compositionstart="handleComposition"
                @compositionupdate="handleComposition"
                @compositionend="handleComposition"
                @input="handleInput"
                @change="handleChange"
                @mouseenter="handleMouseenter">
            <div :class="[prefixCls + '-group-append']" v-if="append" v-show="slotReady"><slot name="append"></slot></div>
            <div :class="[prefixCls + '-group-append', prefixCls + '-search']" v-else-if="search && enterButton" @click="handleSearch">
                <i class="zz-icon zz-icon-ios-search" v-if="enterButton === true"></i>
                <template v-else>{{ enterButton }}</template>
            </div>
            <span class="zz-input-prefix" v-else-if="showPrefix">
                <slot name="prefix"><i class="zz-icon" :class="['zz-icon-' + prefix]" v-if="prefix"></i>
                </slot>
            </span>
            <span v-if="unit !== ''" :class="`${prefixCls}-unit`">{{unit}}</span>
            <span :class="`${prefixCls}-error-icon`" v-else-if="showErrorIcon">
                <i class="zz-icon zz-icon-f-warning"></i>
            </span>
        </template>
    </div>
</template>
<script>
    import { oneOf, findComponentUpward, IEVersion, isPlaceholderNeedToolTip } from '../../utils/assist';
    import calcTextareaHeight from '../../utils/calcTextareaHeight';
    import Emitter from '../../mixins/emitter';

    const prefixCls = 'zz-input';

    export default {
        name: 'Input',
        mixins: [ Emitter ],
        props: {
            // 校验错误信息的时候，是否在输入文本域后面显示感叹号Icon
            showErrorIcon: {
                type: Boolean,
                default: false
            },
            // 是否在输入框后面显示单位，如果有值就显示，为空就不显示
            unit: {
                type: String,
                default: ''
            },
            type: {
                validator (value) {
                    return oneOf(value, ['text', 'textarea', 'password', 'url', 'email', 'date']);
                },
                default: 'text'
            },
            value: {
                type: [String, Number, undefined],
                default: ''
            },
            size: {
                validator (value) {
                    return oneOf(value || 'default', ['small', 'large', 'default']);
                },
                default () {
                    return 'default';
                }
            },
            placeholder: {
                type: String,
                default: ''
            },
            maxlength: {
                type: [String, Number]
            },
            disabled: {
                type: Boolean,
                default: false
            },
            noEmitBlur: {
                type: Boolean,
                default: false
            },
            noEmitChange: {
                type: Boolean,
                default: false
            },
            icon: String,
            autosize: {
                type: [Boolean, Object],
                default: false
            },
            rows: {
                type: Number,
                default: 2
            },
            readonly: {
                type: Boolean,
                default: false
            },
            name: {
                type: String
            },
            number: {
                type: Boolean,
                default: false
            },
            autofocus: {
                type: Boolean,
                default: false
            },
            spellcheck: {
                type: Boolean,
                default: false
            },
            autocomplete: {
                type: String,
                default: 'off'
            },
            clearable: {
                type: Boolean,
                default: true
            },
            elementId: {
                type: String
            },
            wrap: {
                validator (value) {
                    return oneOf(value, ['hard', 'soft']);
                },
                default: 'soft'
            },
            prefix: {
                type: String,
                default: ''
            },
            suffix: {
                type: String,
                default: ''
            },
            search: {
                type: Boolean,
                default: false
            },
            iconShowRight: {
                type: Boolean,
                default: false
            },
            enterButton: {
                type: [Boolean, String],
                default: false
            },
            onPaste: {
                type: Function
            },
            beforeInput: {
                type: Function
            },
            showWordLimit: {
                type: Boolean,
                default: true
            },
            wordLimitBreak: {
                type: Boolean,
                default: true
            },
            iconAlwaysShow: {
                type: Boolean,
                default: false 
            }
        },
        data () {
            return {
                currentValue: this.value,
                currentPlaceholder: this.placeholder,
                prefixCls: prefixCls,
                prepend: true,
                append: true,
                slotReady: false,
                textareaStyles: {},
                showPrefix: false,
                showSuffix: false,
                isOnComposition: false,
                popTipContent: this.placeholder,
                isTooltipDisabled: false,
                isInputHasVal: false
            };
        },
        computed: {
            isIconShow() {
                return !this.disabled || this.iconAlwaysShow;
            },
            wrapClasses () {
                return [
                    `${prefixCls}-wrapper`,
                    {
                        [`${prefixCls}-wrapper-${this.size}`]: !!this.size,
                        [`${prefixCls}-type-${this.type}`]: this.type,
                        [`${prefixCls}-group`]: this.prepend || this.append || (this.search && this.enterButton),
                        [`${prefixCls}-group-${this.size}`]: (this.prepend || this.append || (this.search && this.enterButton)) && !!this.size,
                        [`${prefixCls}-group-with-prepend`]: this.prepend,
                        [`${prefixCls}-group-with-append`]: this.append || (this.search && this.enterButton),
                        [`${prefixCls}-hide-icon`]: this.append,  // #554
                        [`${prefixCls}-with-search`]: (this.search && this.enterButton),
                        [`${prefixCls}-is-content`]: this.currentValue,
                        [`${prefixCls}-wrapper-width-suffix-search`]: this.search && this.enterButton === false && this.iconShowRight === true // #685
                    }
                ];
            },
            inputClasses () {
                return [
                    `${prefixCls}`,
                    {
                        [`${prefixCls}-${this.size}`]: !!this.size,
                        [`${prefixCls}-disabled`]: this.disabled,
                        [`${prefixCls}-with-prefix`]: this.showPrefix,
                        [`${prefixCls}-with-suffix`]: this.showSuffix || (this.search && this.enterButton === false && this.iconShowRight === true),
                        [`${prefixCls}-with-prefix-search`]: this.search && this.enterButton === false && this.iconShowRight === false,
                        [`${prefixCls}-with-suffix-search`]: this.search && this.enterButton === false && this.iconShowRight === true
                    }
                ];
            },
            textareaClasses () {
                return [
                    `${prefixCls}`,
                    {
                        [`${prefixCls}-disabled`]: this.disabled,
                    }
                ];
            },
            textareaWrapClasses () {
                return [
                    `${prefixCls}-textarea-wrapper`,
                    {
                        [`${prefixCls}-beyond-limit`]: typeof this.maxlength === 'number' && this.showWordLimit && this.valueLength > this.maxlength,
                    }
                ];
            },
            searchIconClasses () {
                return [
                    `${prefixCls}-icon`,
                    `${prefixCls}-icon-normal`,
                    {
                        [`${prefixCls}-search-icon`]: !this.iconShowRight,
                        [`${prefixCls}-search-icon-suffix`]: this.iconShowRight,
                        [`${prefixCls}-search-icon-suffix-disabled`]: this.iconShowRight && this.disabled,
                    }
                ];
            },
            difEmpty() {
                let suffix = this.suffix || this.$slots.suffix || this.icon;
                return suffix ? 'showDifEmpty' : '';
            },
            valueLength() {
                return typeof this.currentValue !== 'undefined' ? this.currentValue.toString().length : 0;
            },
            wordLimit() {
                return `${this.valueLength}/${this.maxlength}`;
            },
            textareaMaxLength() {
                return this.wordLimitBreak ? this.maxlength : undefined;
            }
        },
        methods: {
            handleMouseenter() {
                if(this.isInputHasVal) {
                    this.isTooltipDisabled = isPlaceholderNeedToolTip(this.$refs.input, this.placeholder);
                } else {
                    this.isTooltipDisabled = true;
                }
            },
            handlePaste(event) {
                if(this.onPaste) {
                    this.onPaste(event);
                }
            },
            handleEnter (event) {
                this.$emit('on-enter', event);
                if (this.search) this.$emit('on-search', this.currentValue);
            },
            handleKeydown (event) {
                this.$emit('on-keydown', event);
            },
            handleKeypress(event) {
                this.$emit('on-keypress', event);
            },
            handleKeyup (event) {
                this.$emit('on-keyup', event);
            },
            handleIconClick (event) {
                if (this.disabled) return false;
                this.$emit('on-click', event, this.currentValue);
            },
            handleClick() {
                this.inter && clearInterval(this.inter);
                this.clicked = true;
                this.timer && clearTimeout(this.timer);
                this.timer = setTimeout(()=> {
                    this.clicked = false;
                }, 800);
                if(!this.disabled && IEVersion !== -1) {
                    // 如果是IE，清空placeholder
                    this.currentPlaceholder = '';
                }
            },
            handleFocus (event) {
                this.$emit('on-focus', event);
            },
            handleBlur (event) {
                if (IEVersion !== -1) {
                    this.currentPlaceholder = this.placeholder;
                }
                this.inter && clearInterval(this.inter);
                this.$emit('on-blur', event);
                if (!findComponentUpward(this, ['DatePicker', 'TimePicker', 'Cascader', 'Search'])) {
                    this.dispatch('FormItem', 'on-form-blur', this.currentValue);
                }
            },
            handleComposition(event) {
                if (event.type === 'compositionstart') {
                    this.isOnComposition = true;
                }
                if (event.type === 'compositionend') {
                    this.isOnComposition = false;
                    this.handleInput(event);
                }
            },
            handleInput (event) {
                if (this.isOnComposition) return;

                if(this.beforeInput) {
                    this.beforeInput(event);
                }
                let value = event.target.value;
                if (this.number && value !== '') value = Number.isNaN(Number(value)) ? value : Number(value);

                this.isInputHasVal = value ? true : false;

                // fix ie聚焦和失焦触发on-change

                const oldValue = this.value;

                this.$emit('input', value);
                this.setCurrentValue(value);

                // fix ie聚焦和失焦触发on-change
                if(oldValue === value) return;
                this.$emit('on-change', event);
            },
            handleChange (event) {
                this.$emit('on-input-change', event);
            },
            setCurrentValue (value) {
                if (value === this.currentValue) return;
                this.$nextTick(() => {
                    this.resizeTextarea();
                });
                this.currentValue = value;
                if (!findComponentUpward(this, ['DatePicker', 'TimePicker', 'Cascader', 'Search'])) {
                    if (!this.noEmitChange) {
                        this.dispatch('FormItem', 'on-form-change', value);
                    }
                }
            },
            resizeTextarea () {
                const autosize = this.autosize;
                if (!autosize || this.type !== 'textarea') {
                    return false;
                }

                const minRows = autosize.minRows;
                const maxRows = autosize.maxRows;

                this.textareaStyles = calcTextareaHeight(this.$refs.textarea, minRows, maxRows);
            },
            focus () {
                if (this.type === 'textarea') {
                    this.$refs.textarea.focus();
                } else {
                    this.$refs.input.focus();
                }
            },
            blur () {
                if (this.type === 'textarea') {
                    this.$refs.textarea.blur();
                } else {
                    this.$refs.input.blur();
                }
            },
            handleClear () {
                this.isInputHasVal = false;
                const e = { target: { value: '' } };
                this.$emit('input', '');
                this.setCurrentValue('');
                this.$emit('on-change', e, this.currentValue);
                this.$emit('on-clear');
            },
            handleSearch () {
                if (this.disabled) return false;
                this.$refs.input.focus();
                this.$emit('on-search', this.currentValue);
            },
            handleValueChange (val) {
                this.inter && clearInterval(this.inter);
                this.setCurrentValue(val);
            }
        },
        watch: {
            value (val) {
                this.handleValueChange(val);
            },
            placeholder(val) {
                this.currentPlaceholder = val;
            },
            currentPlaceholder(val, oldVal) {
                if(val === '' && oldVal !== '' && !this.disabled) {
                    // 表示是激活了，触发定时器，兼容IE
                    this.inter && clearInterval(this.inter);
                    if (IEVersion() !== -1) {
                        this.inter = setInterval(()=> {
                            if(!this.clicked && this.$refs.input && document.body !== document.activeElement && this.$refs.input !== document.activeElement) {
                                // 表示当前已经不是选中状态，重置placeholder,并清空定时器
                                this.currentPlaceholder = this.placeholder;
                                clearInterval(this.inter);
                            } else if (!this.clicked && this.$refs.textarea && document.body !== document.activeElement && this.$refs.textarea !== document.activeElement ) {
                                // 表示当前已经不是选中状态，重置placeholder，并清空定时器
                                this.currentPlaceholder = this.placeholder;
                                clearInterval(this.inter); 
                            }
                        }, 500);
                    } else {
                        this.inter && clearInterval(this.inter);
                    }
                }
            }
        },
        mounted () {
            if (this.type !== 'textarea') {
                this.prepend = !!this.$slots.prepend;
                this.append = !!this.$slots.append;
                this.showPrefix = this.prefix !== '' || this.$slots.prefix !== undefined;
                this.showSuffix = this.suffix !== '' || this.$slots.suffix !== undefined;
            } else {
                this.prepend = false;
                this.append = false;
            }
            this.slotReady = true;
            this.resizeTextarea();
        }, 
        beforeDestroy() {
            this.timer && clearTimeout(this.timer);
            this.inter && clearInterval(this.inter);
        }
    };
</script>
