import _defineProperty from 'babel-runtime/helpers/defineProperty';
import _extends from 'babel-runtime/helpers/extends';
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
import _createClass from 'babel-runtime/helpers/createClass';
import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
import _inherits from 'babel-runtime/helpers/inherits';
var _jsxFileName = 'src/form/formCreator.jsx';
import React, { Component } from 'react';
import Validator from '../util/validator';
import PropTypes from 'prop-types';

export default (function (defaultData, ruleset, option) {
    return function (ComposedComponent) {
        var _class, _temp;

        return _temp = _class = function (_Component) {
            _inherits(Form, _Component);

            function Form(props, context) {
                _classCallCheck(this, Form);

                var _this = _possibleConstructorReturn(this, (Form.__proto__ || Object.getPrototypeOf(Form)).call(this, props, context));

                _this.initialized = true;

                _this.updateRules = function (newRules) {
                    _this.validator = new Validator(newRules, option);
                };

                _this.updateItemData = function (name, value, cb) {
                    _this.setState(function (state) {
                        _this.initialized = false;
                        return {
                            formData: _extends({}, state.formData, _defineProperty({}, name, value))
                        };
                    }, function () {
                        return cb && cb(name);
                    });
                };

                _this.updateItemsData = function (newData, cb) {
                    _this.setState(function (state) {
                        return {
                            formData: _extends({}, state.formData, newData)
                        };
                    }, function () {
                        return cb && cb();
                    });
                };

                _this.initialize = function () {
                    var newData = _this.defaultData || {};
                    _this.validator.cancelAll();
                    _this.setState(function (state) {
                        _this.initialized = true;
                        return {
                            formData: _extends({}, newData),
                            errorMsg: {},
                            formValidatingStatus: {}
                        };
                    });
                };

                _this.validationResultHandler = function (error, name, promiseValue) {
                    _this.setState(function (state) {
                        return {
                            errorMsg: _extends({}, state.errorMsg, _defineProperty({}, name, error))
                        };
                    });
                };

                _this.validationLoadingHandler = function (isLoading, cb) {
                    return function (result, name, promiseValue) {
                        _this.setState(function (state) {
                            return {
                                formValidatingStatus: _extends({}, state.formValidatingStatus, _defineProperty({}, name || result, isLoading))
                            };
                        });
                        cb && cb(result, name, promiseValue);
                    };
                };

                _this.validateItem = function (cb) {
                    return function (name) {
                        var formData = _this.state.formData;

                        var validation = _this.validator.validateItem(formData, name, _this.validationLoadingHandler(true), _this.validationLoadingHandler(false, cb), function () {}, _this.validationResultHandler);
                        return validation;
                    };
                };

                _this.validate = function (name, value) {
                    var _this$state = _this.state,
                        formData = _this$state.formData,
                        errorMsg = _this$state.errorMsg,
                        formValidatingStatus = _this$state.formValidatingStatus;

                    return _this.validator.asyncValidate(Object.assign(formData, _defineProperty({}, name, value)), function (error, name, isAsync) {
                        _this.setState({
                            formData: _extends({}, formData, _defineProperty({}, name, value)),
                            errorMsg: _extends({}, errorMsg, error)
                        });
                        if (isAsync) {
                            _this.setState({
                                formValidatingStatus: _extends({}, formValidatingStatus, _defineProperty({}, name, false))
                            });
                        }
                    }, [name], function (error, name) {
                        _this.setState({
                            formValidatingStatus: _extends({}, formValidatingStatus, _defineProperty({}, name, true))
                        });
                    });
                };

                _this.validateAll = function (cb) {
                    var formData = _this.state.formData;

                    return _this.validator.asyncValidate(formData, _this.validationLoadingHandler(true), _this.validationLoadingHandler(false), _this.validationResultHandler);
                };

                _this.itemWrapper = function (name) {
                    var validatedProp = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'defaultValue';
                    var _this$state2 = _this.state,
                        formData = _this$state2.formData,
                        errorMsg = _this$state2.errorMsg,
                        formValidatingStatus = _this$state2.formValidatingStatus;

                    return function (InputEl) {
                        var validateStatus = 'initial';
                        if (errorMsg[name] && errorMsg[name].length > 0) {
                            validateStatus = 'error';
                        } else if (errorMsg[name] != null) {
                            validateStatus = 'success';
                        }
                        var newProps = {
                            name: name,
                            validateStatus: validateStatus,
                            formValidatingStatus: formValidatingStatus[name],
                            inputProps: _defineProperty({}, validatedProp, formData[name])
                        };
                        if (errorMsg[name] && errorMsg[name].length > 0) {
                            newProps.helperText = errorMsg[name];
                        }
                        return React.cloneElement(InputEl, newProps);
                    };
                };

                _this.submit = function (onSubmitSuccess, onSubmitFail) {
                    return function () {
                        _this.setState({
                            isSubmitting: true
                        });
                        return _this.validateAll().then(function () {
                            return onSubmitSuccess(_this.state.formData);
                        }, onSubmitFail).then(function () {
                            for (var _len = arguments.length, values = Array(_len), _key = 0; _key < _len; _key++) {
                                values[_key] = arguments[_key];
                            }

                            _this.setState({
                                isSubmitting: false
                            });
                            return values;
                        }, function () {
                            _this.setState({
                                isSubmitting: false
                            });
                            return Promise.reject.apply(Promise, arguments);
                        });
                    };
                };

                var data = props.defaultData ? props.defaultData : defaultData;
                _this.defaultData = data;
                var rules = props.ruleset ? props.ruleset : ruleset;
                _this.state = {
                    formData: _extends({}, data),
                    errorMsg: {},
                    formValidatingStatus: {},
                    isSubmitting: false
                };
                _this.validator = new Validator(rules, option);
                _this.lastValidation = {};
                return _this;
            }

            _createClass(Form, [{
                key: 'componentDidMount',
                value: function componentDidMount() {
                    var formRef = this.props.formRef;

                    formRef && formRef(this);
                }
            }, {
                key: 'componentWillUnmount',
                value: function componentWillUnmount() {
                    var formRef = this.props.formRef;

                    formRef && formRef(null);
                }
            }, {
                key: 'getChildContext',
                value: function getChildContext() {
                    var _state = this.state,
                        formData = _state.formData,
                        errorMsg = _state.errorMsg,
                        formValidatingStatus = _state.formValidatingStatus;

                    return {
                        nuiFormData: {
                            inline: this.props.inline,
                            formValues: formData,
                            formErrorMsgs: errorMsg,
                            formValidatingStatus: formValidatingStatus,
                            updateItemData: this.updateItemData,
                            validateItem: this.validateItem,
                            validateAll: this.validateAll
                        }
                    };
                }
            }, {
                key: 'componentWillReceiveProps',
                value: function componentWillReceiveProps(nextProps) {
                    var defaultData = nextProps.defaultData,
                        ruleSet = nextProps.ruleSet;

                    if (defaultData && defaultData !== this.props.defaultData) {
                        this.initialized = false;
                        this.setState({
                            formData: _extends({}, defaultData)
                        });
                    }
                    if (ruleSet && ruleSet !== this.props.ruleSet) {
                        this.validator = new Validator(ruleSet, option);
                    }
                }

                //validate方法仅用于测试

            }, {
                key: 'render',
                value: function render() {
                    return React.createElement(ComposedComponent, Object.assign({}, this.state, this.props, {
                        updateRules: this.updateRules,
                        formValues: this.state.formData,
                        formErrors: this.state.errorMsg,
                        isValidating: Object.values(this.state.formValidatingStatus).filter(function (msg) {
                            return msg;
                        }).length > 0,
                        isValid: Object.values(this.state.errorMsg).filter(function (msg) {
                            return msg && msg.length > 0;
                        }).length <= 0,
                        validateAll: this.validateAll,
                        validateOne: this.validateItem(),
                        validateItem: this.validateItem,
                        updateItemData: this.updateItemData,
                        updataItemsData: this.updateItemsData,
                        validate: this.validate,
                        initialize: this.initialize,
                        submit: this.submit,
                        isInitialized: this.initialized,
                        __source: {
                            fileName: _jsxFileName,
                            lineNumber: 246
                        },
                        __self: this
                    }));
                }
            }]);

            return Form;
        }(Component), _class.propTypes = {
            inline: PropTypes.bool,
            defaultData: PropTypes.object,
            ruleset: PropTypes.object
        }, _class.defaultProps = {
            inline: false
        }, _class.childContextTypes = {
            nuiFormData: PropTypes.object
        }, _temp;
    };
});