text: 'use strict';
  
  function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
  
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  
  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
  
  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  
  var AsyncTree = require('./AsyncTree');
  /* abstract class */
  
  
  var AsyncObject =
  /*#__PURE__*/
  function () {
    /*
      args: any type (including AsyncObject)
    */
    function AsyncObject() {
      _classCallCheck(this, AsyncObject);
  
      for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
        args[_key] = arguments[_key];
      }
  
      this.args = args;
      this.cache = {};
      this.next = undefined;
      this.asKey = undefined;
    } // TO BE OVERRIDDEN
  
  
    _createClass(AsyncObject, [{
      key: "asyncCall",
      value: function asyncCall() {
        throw new Error('asyncCall or syncCall must be defined');
      }
    }, {
      key: "syncCall",
      value: function syncCall() {
        throw new Error('asyncCall or syncCall must be defined');
      }
    }, {
      key: "onError",
      value: function onError(error) {
        throw error;
      }
    }, {
      key: "onResult",
      value: function onResult(result) {
        return result;
      }
      /*
        Works only if this.continueAfterFail returns true
          (in that case this.onError and this.onResult will be ignored),
      */
  
    }, {
      key: "onErrorAndResult",
      value: function onErrorAndResult(error, result) {
        return error || result;
      }
      /*
        If it returns true, then this.onError and this.onResult will be ignored,
        and the represented result of this object
        will be returned by this.onErrorAndResult.
      */
  
    }, {
      key: "continueAfterFail",
      value: function continueAfterFail() {
        return false;
      }
    }, {
      key: "callbackWithError",
      value: function callbackWithError() {
        return true;
      } // PUBLIC API
  
    }, {
      key: "call",
      value: function call() {
        this.propagateCache(this);
        new AsyncTree(this).create().call();
      }
    }, {
      key: "after",
      value: function after(asyncObject) {
        this.next = asyncObject;
        return this;
      }
    }, {
      key: "as",
      value: function as(key) {
        this.asKey = key;
        return this;
      } // NOT ALLOWED TO BE OVERRIDDEN
  
    }, {
      key: "iterateArgs",
      value: function iterateArgs(func) {
        var _this = this;
  
        this.args.forEach(function (arg, index) {
          func(arg, index, _this.isAsyncObject(arg), _this.isEvent(arg));
        });
      }
    }, {
      key: "hasNoArgs",
      value: function hasNoArgs() {
        return this.args.length === 0;
      }
    }, {
      key: "readyToBeInvoked",
      value: function readyToBeInvoked(readyResultsNum) {
        return this.args.length === readyResultsNum;
      }
    }, {
      key: "callNextTreeIfExists",
      value: function callNextTreeIfExists() {
        if (this.next) {
          this.propagateCache(this.next);
          new AsyncTree(this.next).create().call();
        }
      }
    }, {
      key: "propagateCache",
      value: function propagateCache(arg) {
        var _this2 = this;
  
        if (this.isAsyncObject(arg)) {
          arg.withCache(this.cache);
          arg.iterateArgs(function (arg) {
            return _this2.propagateCache(arg);
          });
        }
      }
    }, {
      key: "withCache",
      value: function withCache(cache) {
        this.cache = cache;
        return this;
      }
    }, {
      key: "saveValueIntoCacheIfNeeded",
      value: function saveValueIntoCacheIfNeeded(value) {
        if (this.asKey) {
          this.cache[this.asKey] = value;
        }
  
        return this;
      }
    }, {
      key: "isAsyncObject",
      value: function isAsyncObject(arg) {
        return this.classChain(arg).indexOf('AsyncObject') !== -1;
      }
    }, {
      key: "isEvent",
      value: function isEvent(arg) {
        return this.classChain(arg).indexOf('Event') !== -1;
      }
    }, {
      key: "classChain",
      value: function classChain(obj, chain) {
        if (!chain) {
          chain = [];
        }
  
        if (typeof obj === 'function') {
          if (!obj.name || obj === Object) {
            return chain;
          }
  
          return this.classChain(Object.getPrototypeOf(obj), chain.concat(obj.name));
        }
  
        if (_typeof(obj) === 'object' && obj !== null) {
          return this.classChain(obj.constructor, chain);
        }
  
        return chain;
      }
    }]);
  
    return AsyncObject;
  }();
  
  module.exports = AsyncObject;
  