import _extends from 'babel-runtime/helpers/extends';
import _toConsumableArray from 'babel-runtime/helpers/toConsumableArray';
import _typeof from 'babel-runtime/helpers/typeof';
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
import _createClass from 'babel-runtime/helpers/createClass';

var Validator = function () {
    function Validator() {
        var ruleSet = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
        var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { first: true, cover: true, parallel: false };

        _classCallCheck(this, Validator);

        if ((typeof ruleSet === 'undefined' ? 'undefined' : _typeof(ruleSet)) !== 'object') {
            throw new Error('RuleSet must be an object!');
        }
        this.ruleSet = ruleSet;
        this.option = option;
        this.lastValidator = {};
    }

    _createClass(Validator, [{
        key: 'messageHandler',
        value: function messageHandler(result, rule, values, ruleResult) {
            if (typeof rule.message === 'function') {
                result = [].concat(_toConsumableArray(result), [('' + (rule.message.apply(rule, _toConsumableArray(values).concat([ruleResult])) || 'Error!')).trim()]);
            } else {
                result = [].concat(_toConsumableArray(result), [('' + (rule.message || 'Error!')).trim()]);
            }
            return result;
        }
    }, {
        key: 'cancelItem',
        value: function cancelItem(name) {
            this.lastValidator[name] = null;
        }
    }, {
        key: 'cancelAll',
        value: function cancelAll() {
            this.lastValidator = {};
        }
    }, {
        key: 'validateItem',
        value: function validateItem(target, name, itemWillValidate, itemDidValidate, itemDidCatch, ruleDidExecute) {
            var _this = this;

            var result = [];
            var promiseQuene = void 0;
            var itemConfig = this.ruleSet[name];
            var rules = void 0;
            if (itemConfig && !Array.isArray(itemConfig)) {
                rules = [itemConfig];
            } else if (Array.isArray(itemConfig)) {
                rules = itemConfig;
            } else if (!itemConfig || itemConfig.length < 1) {
                return;
            }
            // let hasError = false;
            itemWillValidate && itemWillValidate(name);
            var transformToPromise = function transformToPromise(origin, rule, ruleTarget) {
                var isAsync = true;
                if (!origin || !origin.then || !origin.catch) {
                    isAsync = false;
                    origin = origin ? Promise.resolve(origin) : Promise.reject(origin);
                }
                return origin.then(function (promiseValue) {
                    (!_this.option.cover || _this.lastValidator[name] === promiseQuene) && ruleDidExecute && ruleDidExecute(result, name, isAsync, promiseValue);
                    return {
                        result: result,
                        name: name,
                        ruleTarget: ruleTarget,
                        isAsync: isAsync,
                        promiseValue: promiseValue
                    };
                }, function (promiseValue) {
                    // hasError = true;
                    result = _this.messageHandler(result, rule, ruleTarget, promiseValue);
                    (!_this.option.cover || _this.lastValidator[name] === promiseQuene) && ruleDidExecute && ruleDidExecute(result, name, promiseValue);
                    return Promise.reject({
                        result: result,
                        name: name,
                        ruleTarget: ruleTarget,
                        isAsync: isAsync,
                        promiseValue: promiseValue
                    });
                });
            };
            if (this.option.parallel) {
                promiseQuene = Promise.all(rules.map(function (rule) {
                    var ruleTarget = [name].concat(_toConsumableArray(rule.join || [])).map(function (item) {
                        return target[item];
                    });
                    return transformToPromise(rule.validator.apply(rule, _toConsumableArray(ruleTarget)), rule, ruleTarget).then(function (value) {
                        return value;
                    }, _this.option.first ? null : function (value) {
                        return value;
                    });
                }));
            } else {
                promiseQuene = rules.reduce(function (quene, rule) {
                    var ruleTarget = [name].concat(_toConsumableArray(rule.join || [])).map(function (item) {
                        return target[item];
                    });
                    return quene.then(function () {
                        return transformToPromise(rule.validator.apply(rule, _toConsumableArray(ruleTarget)), rule, ruleTarget);
                    }, _this.option.first ? null : function () {
                        return transformToPromise(rule.validator.apply(rule, _toConsumableArray(ruleTarget)), rule, ruleTarget);
                    });
                }, Promise.resolve());
            }
            this.lastValidator[name] = promiseQuene;
            return promiseQuene.then(function (promiseValue) {
                (!_this.option.cover || _this.lastValidator[name] === promiseQuene) && itemDidValidate && itemDidValidate(result, name, promiseValue);
                return promiseValue;
            }, function (promiseValue) {
                (!_this.option.cover || _this.lastValidator[name] === promiseQuene) && itemDidCatch && itemDidCatch(result, name, promiseValue);
                (!_this.option.cover || _this.lastValidator[name] === promiseQuene) && itemDidValidate && itemDidValidate(result, name, promiseValue);
                return Promise.reject(promiseValue);
            });
        }
    }, {
        key: 'asyncValidate',
        value: function asyncValidate(target, itemWillValidate, itemDidValidate, ruleDidExecute, specificItem) {
            var _this2 = this;

            var result = {};
            var promises = [];
            (specificItem || Object.keys(this.ruleSet)).forEach(function (name) {
                promises.push(_this2.validateItem(target, name, itemWillValidate, itemDidValidate, function (itemResult, name) {
                    result[name] = itemResult;
                }, ruleDidExecute));
            });
            return Promise.all(promises).catch(function () {
                return Promise.reject(result);
            });
        }
    }, {
        key: 'addRule',
        value: function addRule(newRuleSet) {
            this.ruleSet = _extends({}, this.ruleSet, newRuleSet);
        }
    }, {
        key: 'deleteRule',
        value: function deleteRule(ruleName) {
            delete this.ruleSet[ruleName];
        }
    }]);

    return Validator;
}();

export default Validator;