"use strict";

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

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

var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));

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

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

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

var _iterableUtils = require("../utils/iterable-utils");

var _constants = require("./constants");

var EMPTY_PROPS = Object.freeze({});

var ComponentState = function () {
  function ComponentState(component) {
    (0, _classCallCheck2.default)(this, ComponentState);
    this.component = void 0;
    this.onAsyncPropUpdated = void 0;
    this.asyncProps = void 0;
    this.oldProps = void 0;
    this.oldAsyncProps = void 0;
    this.component = component;
    this.asyncProps = {};

    this.onAsyncPropUpdated = function () {};

    this.oldProps = null;
    this.oldAsyncProps = null;
  }

  var _proto = ComponentState.prototype;

  _proto.finalize = function finalize() {
    for (var _propName in this.asyncProps) {
      var asyncProp = this.asyncProps[_propName];

      if (asyncProp && asyncProp.type && asyncProp.type.release) {
        asyncProp.type.release(asyncProp.resolvedValue, asyncProp.type, this.component);
      }
    }

    this.asyncProps = {};
    this.component = null;
    this.resetOldProps();
  };

  _proto.getOldProps = function getOldProps() {
    return this.oldAsyncProps || this.oldProps || EMPTY_PROPS;
  };

  _proto.resetOldProps = function resetOldProps() {
    this.oldAsyncProps = null;
    this.oldProps = this.component ? this.component.props : null;
  };

  _proto.hasAsyncProp = function hasAsyncProp(propName) {
    return propName in this.asyncProps;
  };

  _proto.getAsyncProp = function getAsyncProp(propName) {
    var asyncProp = this.asyncProps[propName];
    return asyncProp && asyncProp.resolvedValue;
  };

  _proto.isAsyncPropLoading = function isAsyncPropLoading(propName) {
    if (propName) {
      var asyncProp = this.asyncProps[propName];
      return Boolean(asyncProp && asyncProp.pendingLoadCount > 0 && asyncProp.pendingLoadCount !== asyncProp.resolvedLoadCount);
    }

    for (var key in this.asyncProps) {
      if (this.isAsyncPropLoading(key)) {
        return true;
      }
    }

    return false;
  };

  _proto.reloadAsyncProp = function reloadAsyncProp(propName, value) {
    this._watchPromise(propName, Promise.resolve(value));
  };

  _proto.setAsyncProps = function setAsyncProps(props) {
    this.component = props[_constants.COMPONENT_SYMBOL] || this.component;
    var resolvedValues = props[_constants.ASYNC_RESOLVED_SYMBOL] || {};
    var originalValues = props[_constants.ASYNC_ORIGINAL_SYMBOL] || props;
    var defaultValues = props[_constants.ASYNC_DEFAULTS_SYMBOL] || {};

    for (var _propName2 in resolvedValues) {
      var _value = resolvedValues[_propName2];

      this._createAsyncPropData(_propName2, defaultValues[_propName2]);

      this._updateAsyncProp(_propName2, _value);

      resolvedValues[_propName2] = this.getAsyncProp(_propName2);
    }

    for (var _propName3 in originalValues) {
      var _value2 = originalValues[_propName3];

      this._createAsyncPropData(_propName3, defaultValues[_propName3]);

      this._updateAsyncProp(_propName3, _value2);
    }
  };

  _proto._fetch = function _fetch(propName, url) {
    return null;
  };

  _proto._onResolve = function _onResolve(propName, value) {};

  _proto._onError = function _onError(propName, error) {};

  _proto._updateAsyncProp = function _updateAsyncProp(propName, value) {
    if (!this._didAsyncInputValueChange(propName, value)) {
      return;
    }

    if (typeof value === 'string') {
      value = this._fetch(propName, value);
    }

    if (value instanceof Promise) {
      this._watchPromise(propName, value);

      return;
    }

    if ((0, _iterableUtils.isAsyncIterable)(value)) {
      this._resolveAsyncIterable(propName, value);

      return;
    }

    this._setPropValue(propName, value);
  };

  _proto._freezeAsyncOldProps = function _freezeAsyncOldProps() {
    if (!this.oldAsyncProps && this.oldProps) {
      this.oldAsyncProps = Object.create(this.oldProps);

      for (var _propName4 in this.asyncProps) {
        Object.defineProperty(this.oldAsyncProps, _propName4, {
          enumerable: true,
          value: this.oldProps[_propName4]
        });
      }
    }
  };

  _proto._didAsyncInputValueChange = function _didAsyncInputValueChange(propName, value) {
    var asyncProp = this.asyncProps[propName];

    if (value === asyncProp.resolvedValue || value === asyncProp.lastValue) {
      return false;
    }

    asyncProp.lastValue = value;
    return true;
  };

  _proto._setPropValue = function _setPropValue(propName, value) {
    this._freezeAsyncOldProps();

    var asyncProp = this.asyncProps[propName];

    if (asyncProp) {
      value = this._postProcessValue(asyncProp, value);
      asyncProp.resolvedValue = value;
      asyncProp.pendingLoadCount++;
      asyncProp.resolvedLoadCount = asyncProp.pendingLoadCount;
    }
  };

  _proto._setAsyncPropValue = function _setAsyncPropValue(propName, value, loadCount) {
    var asyncProp = this.asyncProps[propName];

    if (asyncProp && loadCount >= asyncProp.resolvedLoadCount && value !== undefined) {
      this._freezeAsyncOldProps();

      asyncProp.resolvedValue = value;
      asyncProp.resolvedLoadCount = loadCount;
      this.onAsyncPropUpdated(propName, value);
    }
  };

  _proto._watchPromise = function _watchPromise(propName, promise) {
    var _this = this;

    var asyncProp = this.asyncProps[propName];

    if (asyncProp) {
      asyncProp.pendingLoadCount++;
      var loadCount = asyncProp.pendingLoadCount;
      promise.then(function (data) {
        if (!_this.component) {
          return;
        }

        data = _this._postProcessValue(asyncProp, data);

        _this._setAsyncPropValue(propName, data, loadCount);

        _this._onResolve(propName, data);
      }).catch(function (error) {
        _this._onError(propName, error);
      });
    }
  };

  _proto._resolveAsyncIterable = function () {
    var _resolveAsyncIterable2 = (0, _asyncToGenerator2.default)(_regenerator.default.mark(function _callee(propName, iterable) {
      var asyncProp, loadCount, data, count, _iteratorAbruptCompletion, _didIteratorError, _iteratorError, _iterator, _step, chunk, dataTransform;

      return _regenerator.default.wrap(function _callee$(_context) {
        while (1) {
          switch (_context.prev = _context.next) {
            case 0:
              if (!(propName !== 'data')) {
                _context.next = 3;
                break;
              }

              this._setPropValue(propName, iterable);

              return _context.abrupt("return");

            case 3:
              asyncProp = this.asyncProps[propName];

              if (asyncProp) {
                _context.next = 6;
                break;
              }

              return _context.abrupt("return");

            case 6:
              asyncProp.pendingLoadCount++;
              loadCount = asyncProp.pendingLoadCount;
              data = [];
              count = 0;
              _iteratorAbruptCompletion = false;
              _didIteratorError = false;
              _context.prev = 12;
              _iterator = (0, _asyncIterator2.default)(iterable);

            case 14:
              _context.next = 16;
              return _iterator.next();

            case 16:
              if (!(_iteratorAbruptCompletion = !(_step = _context.sent).done)) {
                _context.next = 28;
                break;
              }

              chunk = _step.value;

              if (this.component) {
                _context.next = 20;
                break;
              }

              return _context.abrupt("return");

            case 20:
              dataTransform = this.component.props.dataTransform;

              if (dataTransform) {
                data = dataTransform(chunk, data);
              } else {
                data = data.concat(chunk);
              }

              Object.defineProperty(data, '__diff', {
                enumerable: false,
                value: [{
                  startRow: count,
                  endRow: data.length
                }]
              });
              count = data.length;

              this._setAsyncPropValue(propName, data, loadCount);

            case 25:
              _iteratorAbruptCompletion = false;
              _context.next = 14;
              break;

            case 28:
              _context.next = 34;
              break;

            case 30:
              _context.prev = 30;
              _context.t0 = _context["catch"](12);
              _didIteratorError = true;
              _iteratorError = _context.t0;

            case 34:
              _context.prev = 34;
              _context.prev = 35;

              if (!(_iteratorAbruptCompletion && _iterator.return != null)) {
                _context.next = 39;
                break;
              }

              _context.next = 39;
              return _iterator.return();

            case 39:
              _context.prev = 39;

              if (!_didIteratorError) {
                _context.next = 42;
                break;
              }

              throw _iteratorError;

            case 42:
              return _context.finish(39);

            case 43:
              return _context.finish(34);

            case 44:
              this._onResolve(propName, data);

            case 45:
            case "end":
              return _context.stop();
          }
        }
      }, _callee, this, [[12, 30, 34, 44], [35,, 39, 43]]);
    }));

    function _resolveAsyncIterable(_x, _x2) {
      return _resolveAsyncIterable2.apply(this, arguments);
    }

    return _resolveAsyncIterable;
  }();

  _proto._postProcessValue = function _postProcessValue(asyncProp, value) {
    var propType = asyncProp.type;

    if (propType && this.component) {
      if (propType.release) {
        propType.release(asyncProp.resolvedValue, propType, this.component);
      }

      if (propType.transform) {
        return propType.transform(value, propType, this.component);
      }
    }

    return value;
  };

  _proto._createAsyncPropData = function _createAsyncPropData(propName, defaultValue) {
    var asyncProp = this.asyncProps[propName];

    if (!asyncProp) {
      var propTypes = this.component && this.component.props[_constants.PROP_TYPES_SYMBOL];
      this.asyncProps[propName] = {
        type: propTypes && propTypes[propName],
        lastValue: null,
        resolvedValue: defaultValue,
        pendingLoadCount: 0,
        resolvedLoadCount: 0
      };
    }
  };

  return ComponentState;
}();

exports.default = ComponentState;
//# sourceMappingURL=component-state.js.map