"use strict";

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

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.createAsyncRef = createAsyncRef;
exports.createMemoRef = createMemoRef;
exports.isAsyncRef = isAsyncRef;
exports.isKeyPathEqual = isKeyPathEqual;
exports.isMemoRef = isMemoRef;
exports.makeMsg = makeMsg;
exports.ofChain = ofChain;
exports.onlySupportLegacy = onlySupportLegacy;
exports.patchObj = patchObj;
exports.traverseChain = traverseChain;
exports.tryGet = tryGet;

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

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

function traverseChain(Target, TopConstructor, fn) {
  var traverse = function traverse(Target) {
    // if it is a Constructor
    if (!(0, _tsFns.isConstructor)(Target)) {
      Target = (0, _tsFns.getConstructorOf)(Target);
    }

    if (Target === TopConstructor) {
      return;
    }

    fn(Target); // to parent

    var Parent = (0, _tsFns.getConstructorOf)(Target.prototype);

    if ((0, _tsFns.isInheritedOf)(Parent, TopConstructor)) {
      traverse(Target.prototype);
    }
  };

  traverse(Target);
}

function ofChain(target, TopConstructor) {
  var excludes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
  var properties = {};
  var Target = (0, _tsFns.getConstructorOf)(target);
  traverseChain(Target, TopConstructor, function (Meet) {
    (0, _tsFns.each)(Meet, function (descriptor, key) {
      if (key.indexOf('_') === 0) {
        return;
      }

      if (excludes.includes(key)) {
        return;
      }

      if (!Object.getOwnPropertyDescriptor(properties, key)) {
        var prop = key.indexOf('$') === 0 ? key.substring(2) : key;
        (0, _tsFns.define)(properties, prop, descriptor);
      }
    }, true);
  });
  return properties;
}

function tryGet(get, use) {
  try {
    return get();
  } catch (e) {
    return use;
  }
}

function makeMsg(errs) {
  var errors = errs.filter(function (item) {
    return item;
  });

  if (errors.length) {
    errors.message = errors[0].message;
  }

  return errors;
}

function patchObj(source, input) {
  (0, _tsFns.each)(input, function (value, key) {
    var src = source[key];

    if ((0, _tsFns.isArray)(src) && (0, _tsFns.isArray)(value)) {
      src.push.apply(src, (0, _toConsumableArray2.default)(value));
    } else if ((0, _tsFns.isObject)(src) && (0, _tsFns.isObject)(value)) {
      patchObj(src, value);
    } else {
      source[key] = value;
    }
  });
}

function createAsyncRef(defaultValue, getter, deps) {
  var ref = {
    current: defaultValue,
    deferer: null,
    getter: getter,
    deps: deps,
    $$type: 'asyncRef',
    attach: function attach() {
      var _this = this;

      for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
        args[_key] = arguments[_key];
      }

      if (ref.deferer) {
        return ref.deferer;
      }

      var deferer = Promise.resolve().then(function () {
        return getter.call.apply(getter, [_this].concat(args));
      }).then(function (next) {
        ref.current = next;
        return next;
      });
      ref.deferer = deferer; // use it in one microtask

      Promise.resolve().then(function () {
        ref.deferer = null;
      });
      return deferer;
    }
  };
  return ref;
}

function isAsyncRef(ref) {
  return (0, _tsFns.isObject)(ref) && ref.$$type === 'asyncRef';
}

function createMemoRef(getter, compare, depend) {
  var ref = {
    $$type: 'memoRef',
    getter: getter,
    compare: compare,
    depend: depend
  };
  return ref;
}

function isMemoRef(ref) {
  return (0, _tsFns.isObject)(ref) && ref.$$type === 'memoRef';
}

function isKeyPathEqual(keyPath1, keyPath2) {
  if ((0, _tsFns.isString)(keyPath1) && (0, _tsFns.isString)(keyPath2)) {
    return keyPath1 === keyPath2;
  }

  var key1 = (0, _tsFns.isArray)(keyPath1) ? (0, _toConsumableArray2.default)(keyPath1) : (0, _tsFns.makeKeyChain)(keyPath1);
  var key2 = (0, _tsFns.isArray)(keyPath2) ? (0, _toConsumableArray2.default)(keyPath2) : (0, _tsFns.makeKeyChain)(keyPath2);
  var len = Math.max(key1.length, key2.length);

  for (var i = 0; i < len; i++) {
    var path1 = key1[i];
    var path2 = key2[i];

    if (path1 === path2) {
      continue;
    }

    if ((0, _tsFns.isNumeric)(path1) && (0, _tsFns.isNumber)(path2) && path1 === path2 + '') {
      continue;
    }

    if ((0, _tsFns.isNumeric)(path2) && (0, _tsFns.isNumber)(path1) && path2 === path1 + '') {
      continue;
    }

    return false;
  }

  return true;
}

function onlySupportLegacy(target) {
  // new version of decorators
  if (target && target[Symbol.toStringTag] === 'Descriptor') {
    throw new Error("TySheMo: decorators only support legacy(stage 1) version.");
  }
}