"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Rule = void 0;

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));

var _tsFns = require("ts-fns");

var _type = require("./type.js");

var Rule = /*#__PURE__*/function () {
  /**
   * define a rule
   * @param {string} name
   * @param {function} validate return 1.true/false 2.error/null
   * @param {function} override
   * @param {function} complete
   * @param {string|function} message
   */
  function Rule() {
    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    (0, _classCallCheck2.default)(this, Rule);
    var name = options.name,
        pattern = options.pattern,
        message = options.message;
    this.name = name || 'Rule';
    this.pattern = pattern;
    this.message = message;
    this.isStrict = false;
    this.isLoose = false;
    this.options = options;
  }

  (0, _createClass2.default)(Rule, [{
    key: "validate",
    value: function validate(data, key, pattern) {
      var validate = this.options.validate;
      var message = this.message;

      var makeError = function makeError(arg) {
        if (!arg) {
          return null;
        }

        if (message) {
          var msg = (0, _tsFns.isFunction)(message) ? message(data, key) : message;
          var err = new TypeError(msg);
          return err;
        }

        if ((0, _tsFns.isInstanceOf)(arg, Error)) {
          return arg;
        }

        if ((0, _tsFns.isString)(arg)) {
          return new TypeError(arg);
        }
      };

      var error = null;

      if ((0, _tsFns.isInstanceOf)(pattern, Rule)) {
        var rule = this.isStrict && !pattern.isStrict ? pattern.strict : !this.isStrict && this.isLoose && !pattern.isStrict && pattern.isLoose ? pattern.loose : pattern;
        var err = rule.catch(data, key);
        error = makeError(err);
      } else if ((0, _tsFns.isInstanceOf)(pattern, _type.Type)) {
        var type = this.isStrict && !pattern.isStrict ? pattern.strict : !this.isStrict && this.isLoose && !pattern.isStrict && pattern.isLoose ? pattern.loose : pattern;

        var _err = type.catch(data[key]);

        error = makeError(_err);
      } else if ((0, _tsFns.isFunction)(validate)) {
        var res = validate.call(this, data, key);

        if ((0, _tsFns.isBoolean)(res)) {
          if (!res) {
            error = makeError('exception');
          }
        } else if ((0, _tsFns.isInstanceOf)(res, Error)) {
          error = makeError(res);
        }
      }

      return error;
    }
    /**
     * validate value twice
     * @param {*} data
     * @param {*} key
     */

  }, {
    key: "catch",
    value: function _catch(data, key) {
      var _this$options = this.options,
          shouldcheck = _this$options.shouldcheck,
          use = _this$options.use,
          decorate = _this$options.decorate,
          override = _this$options.override,
          complete = _this$options.complete; // 1 should check?

      if ((0, _tsFns.isFunction)(shouldcheck) && !shouldcheck.call(this, data, key)) {
        return null;
      } // 2 use


      var pattern = (0, _tsFns.isFunction)(use) ? use.call(this, data, key) : null; // 3 validate

      var error = this.validate(data, key, pattern); // 4 decorate

      if (!error && (0, _tsFns.isFunction)(decorate)) {
        decorate.call(this, data, key);
      } // 5 override


      if (error && (0, _tsFns.isFunction)(override)) {
        override.call(this, data, key);
        error = this.validate(data, key, pattern);
      } // 6 complete


      if ((0, _tsFns.isFunction)(complete)) {
        var err = complete.call(this, data, key, error);
        error = (0, _tsFns.isNull)(err) || err instanceof Error ? err : error;
      }

      return error;
    }
  }, {
    key: "clone",
    value: function clone() {
      var Constructor = (0, _tsFns.getConstructorOf)(this);
      var ins = new Constructor(this.options);
      return ins;
    }
  }, {
    key: "toBeStrict",
    value: function toBeStrict() {
      var mode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
      this.isStrict = !!mode;

      if (mode) {
        this.isLoose = false;
      }

      return this;
    }
  }, {
    key: "strict",
    get: function get() {
      var ins = this.clone().toBeStrict();
      return ins;
    }
  }, {
    key: "Strict",
    get: function get() {
      return this.strict;
    }
  }, {
    key: "toBeLoose",
    value: function toBeLoose() {
      var mode = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;

      if (this.isStrict) {
        console.error('TySheMo: strict Type can not change to be loose.');
        return this;
      }

      this.isLoose = !!mode;
      return this;
    }
  }, {
    key: "loose",
    get: function get() {
      var ins = this.clone().toBeLoose();
      return ins;
    }
  }, {
    key: "Loose",
    get: function get() {
      return this.loose;
    }
  }, {
    key: "toString",
    value: function toString() {
      return this.name;
    }
  }]);
  return Rule;
}();

exports.Rule = Rule;