<template>
    <div class="v-form-item" :class="clazz">
        <label v-if="label" :for="labelFor" :style="{width: offsetLeft + 'px'}">{{label}}</label>
        <div class="v-form-item__input">
            <slot></slot>
            <slot class="v-form-item__error" name="error" :error="error">
                <span></span>
            </slot>
        </div>
    </div>
</template>

<script>
//import Promise from 'any-promise';
import emitter from 'vhtml-ui/src/mixins/emitter';
import Validator from './Validator';

/**
 * VFormItem
 * @author mmzhou
 */
export default {
    name: 'VFormItem',

    mixins: [emitter],

    props: {
        label: String,
        labelWidth: Number,
        labelFor: String,
        /**
         * Form组件model对应的属性
         * 例如：
         *     name             // 普通属性
         *     urls:1           // 数组urls中的第一个
         *     urls:2           // 数组urls中的第二个
         *     person:address   // person对象中的address属性
         * 除了内部不包含输入组件的情况之外，都需要设置此属性
         */
        name: String,
        required: {
            type: String,
            default: ''
        },
        /**
         * 验证规则
         *      [
         *          {required: true, message: '请输入邮箱地址', trigger: 'change'},
         *          {email: true, message: '请输入正确的邮箱地址', trigger: 'change'},
         *          {validate: /regexp/, message: '不符合正则', trigger: 'change'},
         *          {validate: function (value, allValue) {
         *              return Promise.resolve();
         *          }, message: '异步验证', trigger: 'blur', submit: false},
         *
         *      ]
         *
         *      message 代表错误信息
         *      trigger 代码检查触发时机，默认为`change`
         *              可选值为`change,input,blur,focus`
         *              如果是`*`则表示全部
         *              可以一次写多个，例如`input,blur`
         *      submit  是否在提交之前必须通过验证，默认为true
         */
        rules: [Object, Array]
    },
    data() {
        return {
            status: 'default',
            error: ''
        };
    },
    computed: {
        offsetLeft() {
            return this.form.kind === 'inline' ? 0 : (this.labelWidth || this.form.labelWidth);
        },
        clazz() {
            return {
                'is-required': this.required,
                'is-valid': this.status === 'valid',
                'is-invalid': this.status === 'invalid',
            };
        },
        form() {
            let parent = this.$parent;
            while (parent.$options.name !== 'VForm') {
                parent = parent.$parent;
            }
            return parent;
        },
        fieldValue: {
            cache: false,
            get() {
                const model = this.form.model;
                if (!model || !this.prop) {
                    return;
                }
                const temp = this.prop.split(':');
                return temp.length > 1
                    ? model[temp[0]][temp[1]]
                    : model[this.prop];
            }
        }
    },
    methods: {
        validate(trigger) {
            const rules = this.getFilteredRule(trigger);
            if (!rules || rules.length === 0) {
                return Promise.resolve();
            }

            return Validator.validate(rules, this.fieldValue, this.form.model)
                .then(
                    () => {
                        this.status = 'valid';
                    },
                    (error) => {
                        this.status = 'invalid';
                        this.error = error && error.message || '';
                    }
                );
        },
        getRules() {
            let formRules = this.form.rules;
            const selfRuels = this.rules;
            formRules = formRules ? formRules[this.prop] : [];
            const rules = [].concat(selfRuels || formRules || []);
            const hasRequired = (rule) => !!rule.required;
            if (this.required && !rules.some(hasRequired)) {
                // 如果是required的项，那么先检查是否rules中包含了required，如果没有则加入
                rules.unshift({
                    required: true,
                    message: this.required
                });
            }
            return rules;
        },
        getFilteredRule(trigger) {
            const rules = this.getRules();
            return rules.filter(rule => {
                if (trigger === 'submit') {
                    // default is true
                    return rule.submit == null ? true : rule.submit;
                }

                const ruleTrigger = rule.trigger || 'change';
                return ruleTrigger === '*' || ~ruleTrigger.split(',').indexOf(trigger);
            });
        }
    },
    mounted() {
        if (this.prop) {
            this.dispatch('VForm', 'VForm.addField', [this]);

            let rules = this.getRules();
            if (rules.length) {
                return;
            }

            this.$on('VForm.focus', (e) => {
                this.validate('focus');
            });
            this.$on('VForm.blur', (e) => {
                this.validate('blur');
            });
            this.$on('VForm.input', (e) => {
                this.validate('input');
            });
            this.$on('VForm.change', (e) => {
                this.validate('change');
            });
        }
    },
    beforeDestroy() {
        this.dispatch('VForm', 'VForm.removeField', [this]);
    }
};
</script>
