
import '../jquery-form/jquery.form.min';

let formCallbacks = {
        before: [], success: [], error: []
    };

class Form {
    constructor(options) {
        let _this = this;

        _this.options = $.extend({
            // 表单的 jquery 对象或者css选择器
            form: null,
            // 开启表单验证
            validate: false,
            // 确认弹窗
            confirm: {title: null, content: null},
            // 是否使用Toastr展示字段验证错误信息
            validationErrorToastr: false,
            // 表单错误信息class
            errorClass: 'has-error',
            // 表单错误信息容器选择器
            errorContainerSelector: '.with-errors',
            // 表单组css选择器
            groupSelector: '.form-group,.form-label-group,.form-field',
            // tab表单css选择器
            tabSelector: '.tab-pane',
            // 错误信息模板
            errorTemplate: '<label class="control-label" for="inputError"><i class="feather icon-x-circle"></i> {message}</label><br/>',
            // 是否允许跳转
            redirect: true,
            // 自动移除表单错误信息
            autoRemoveError: true,
            // 表单提交之前事件监听，返回false可以中止表单继续提交
            before: function () {},
            // 表单提交之后事件监听，返回false可以中止后续逻辑
            after: function () {},
            // 成功事件，返回false可以中止后续逻辑
            success: function () {},
            // 失败事件，返回false可以中止后续逻辑
            error: function () {},
        }, options);

        _this.originalValues = {};
        _this.$form = $(_this.options.form).first();
        _this._errColumns = {};

        _this.init();
    }

    init() {
        let _this = this;
        let confirm = _this.options.confirm;

        if (! confirm.title) {
            return _this.submit();
        }

        Dcat.confirm(confirm.title, confirm.content, function () {
            _this.submit();
        });
    }

    submit() {
        let _this = this,
            $form = _this.$form,
            options = _this.options,
            $submitButton = $form.find('[type="submit"],.submit');

        // 移除所有错误信息
        _this.removeErrors();

        $form.ajaxSubmit({
            beforeSubmit: function (fields, form, _opt) {
                if (options.before(fields, form, _opt, _this) === false) {
                    return false;
                }

                // 触发全局事件
                if (fire(formCallbacks.before, fields, form, _opt, _this) === false) {
                    return false;
                }

                // 开启表单验证
                if (options.validate) {
                    $form.validator('validate');

                    if ($form.find('.' + options.errorClass).length > 0) {
                        return false;
                    }
                }

                $submitButton.buttonLoading();
            },
            success: function (response) {
                setTimeout(function () {
                    $submitButton.buttonLoading(false);
                }, 700);

                if (options.after(true, response, _this) === false) {
                    return;
                }

                if (options.success(response, _this) === false) {
                    return;
                }

                if (fire(formCallbacks.success, response, _this) === false) {
                    return;
                }

                if (response.redirect === false || ! options.redirect) {
                    if (response.data && response.data.then) {
                        delete response.data['then'];
                        delete response.data['then'];
                        delete response.data['then'];
                    }
                }

                Dcat.handleJsonResponse(response);
            },
            error: function (response) {
                $submitButton.buttonLoading(false);

                if (options.after(false, response, _this) === false) {
                    return;
                }

                if (options.error(response, _this) === false) {
                    return;
                }

                if (fire(formCallbacks.error, response, _this) === false) {
                    return;
                }

                try {
                    var error = JSON.parse(response.responseText),
                        key;

                    if (response.status != 422 || ! error || ! Dcat.helpers.isset(error, 'errors')) {
                        return Dcat.error(response.status + ' ' + response.statusText);
                    }
                    error = error.errors;

                    for (key in error) {
                        // 显示错误信息
                        _this._errColumns[key] = _this.showError($form, key, error[key]);
                    }

                } catch (e) {
                    return Dcat.error(response.status + ' ' + response.statusText);
                }
            }
        });
    }

    // 显示错误信息
    showError($form, column, errors) {
        let _this = this,
            $field = _this.queryFieldByName($form, column),
            $group = $field.closest(_this.options.groupSelector),
            render = function (msg) {
                $group.addClass(_this.options.errorClass);

                if (typeof msg === 'string') {
                    msg = [msg];
                }

                for (let j in msg) {
                    $group.find(_this.options.errorContainerSelector).first().append(
                        _this.options.errorTemplate.replace('{message}', msg[j])
                    );
                }

                if (_this.options.validationErrorToastr) {
                    Dcat.error(msg.join('<br/>'));
                }
            };

        queryTabTitleError(_this, $field).removeClass('d-none');

        // 保存字段原始数据
        _this.originalValues[column] = _this.getFieldValue($field);

        if (! $field) {
            if (Dcat.helpers.len(errors) && errors.length) {
                Dcat.error(errors.join("  \n  "));
            }
            return;
        }

        render(errors);

        if (_this.options.autoRemoveError) {
            removeErrorWhenValChanged(_this, $field, column);
        }

        return $field;
    }

    // 获取字段值
    getFieldValue($field) {
        let vals = [],
            type = $field.attr('type'),
            checker = type === 'checkbox' || type === 'radio',
            i;

        for (i = 0; i < $field.length; i++) {
            if (checker) {
                vals.push($($field[i]).prop('checked'));
                continue;
            }

            vals.push($($field[i]).val());
        }

        return vals;
    }

    // 判断值是否改变
    isValueChanged($field, column) {
        return ! Dcat.helpers.equal(this.originalValues[column], this.getFieldValue($field));
    }

    // 获取字段jq对象
    queryFieldByName($form, column) {
        if (column.indexOf('.') !== -1) {
            column = column.split('.');

            let first = column.shift(),
                i,
                sub = '';

            for (i in column) {
                sub += '[' + column[i] + ']';
            }
            column = first + sub;
        }

        var $c = $form.find('[name="' + column + '"]');

        if (!$c.length) $c = $form.find('[name="' + column + '[]"]');

        if (!$c.length) {
            $c = $form.find('[name="' + column.replace(/start$/, '') + '"]');
        }
        if (!$c.length) {
            $c = $form.find('[name="' + column.replace(/end$/, '') + '"]');
        }

        if (!$c.length) {
            $c = $form.find('[name="' + column.replace(/start\]$/, ']') + '"]');
        }
        if (!$c.length) {
            $c = $form.find('[name="' + column.replace(/end\]$/, ']') + '"]');
        }

        return $c;
    }

    // 移除给定字段的错误信息
    removeError($field, column) {
        let options = this.options,
            parent = $field.parents(options.groupSelector),
            errorClass = this.errorClass;

        parent.removeClass(errorClass);
        parent.find(options.errorContainerSelector).html('');

        // tab页下没有错误信息了，隐藏title的错误图标
        let tab;

        if (! queryTabByField(this, $field).find('.'+errorClass).length) {
            tab = queryTabTitleError(this, $field);
            if (! tab.hasClass('d-none')) {
                tab.addClass('d-none');
            }
        }

        delete this._errColumns[column];
    }

    // 删除所有错误信息
    removeErrors() {
        let _this = this,
            column,
            tab;

        // 移除所有字段的错误信息
        _this.$form.find(_this.options.errorContainerSelector).each(function (_, $err) {
            $($err).parents(_this.options.groupSelector).removeClass(_this.options.errorClass);
            $($err).html('');
        });

        // 移除tab表单tab标题错误信息
        for (column in _this._errColumns) {
            tab = queryTabTitleError(_this._errColumns[column]);
            if (! tab.hasClass('d-none')) {
                tab.addClass('d-none');
            }
        }

        // 重置
        _this._errColumns = {};
    }
}

// 监听表单提交事件
Form.submitting = function (callback) {
    typeof callback == 'function' && (formCallbacks.before.push(callback));

    return this
};

// 监听表单提交完毕事件
Form.submitted = function (success, error) {
    typeof success == 'function' && (formCallbacks.success.push(success));
    typeof error == 'function' && (formCallbacks.error.push(error));

    return this
};

// 当字段值变化时移除错误信息
function removeErrorWhenValChanged(form, $field, column) {
    let remove = function () {
        form.removeError($field, column)
    };

    $field.one('change', remove);
    $field.off('blur', remove).on('blur', function () {
        if (form.isValueChanged($field, column))  {
            remove();
        }
    });

    // 表单值发生变化就移除错误信息
    let interval = function () {
        setTimeout(function () {
            if (! $field.length) {
                return;
            }
            if (form.isValueChanged($field, column)) {
                return remove();
            }

            interval();
        }, 500);
    };

    interval();
}


function getTabId(form, $field) {
    return $field.parents(form.options.tabSelector).attr('id');
}

function queryTabByField(form, $field)
{
    let tabId = getTabId(form, $field);

    if (! tabId) {
        return $('<none></none>');
    }

    return $(`a[href="#${tabId}"]`);
}

function queryTabTitleError(form, $field) {
    return queryTabByField(form, $field).find('.has-tab-error');
}

// 触发钩子事件
function fire(callbacks) {
    let i, j,
        result,
        args = arguments,
        argsArr = [];

    delete args[0];

    args = args || [];

    for (j in args) {
        argsArr.push(args[j]);
    }

    for (i in callbacks) {
        result = callbacks[i].apply(callbacks[i], argsArr);

        if (result === false) {
            return result; // 返回 false 会代码阻止继续执行
        }
    }
}


// 开启form表单模式
$.fn.form = function (options) {
    let $this = $(this);

    options = $.extend(options, {
        form: $this,
    });

    $this.on('submit', function () {
        return false;
    });

    $this.find('[type="submit"],.submit').click(function (e) {
        Dcat.Form(options);

        return false;
    });
};

export default Form
