'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _regenerator = require('babel-runtime/regenerator');

var _regenerator2 = _interopRequireDefault(_regenerator);

var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');

var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);

var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');

var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);

var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

var _createClass2 = require('babel-runtime/helpers/createClass');

var _createClass3 = _interopRequireDefault(_createClass2);

var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');

var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);

var _get2 = require('babel-runtime/helpers/get');

var _get3 = _interopRequireDefault(_get2);

var _inherits2 = require('babel-runtime/helpers/inherits');

var _inherits3 = _interopRequireDefault(_inherits2);

var _objectWithoutProperties2 = require('babel-runtime/helpers/objectWithoutProperties');

var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2);

var _Fetcher = require('./Fetcher');

var _Fetcher2 = _interopRequireDefault(_Fetcher);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

// Always call this with `new` to make the abstraction over the inner class
// transparent to module consumers
var ExhaustivePaginatedFetcher = function ExhaustivePaginatedFetcher() {
  var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

  var _ref$SuperClass = _ref.SuperClass,
      SuperClass = _ref$SuperClass === undefined ? _Fetcher2.default : _ref$SuperClass,
      args = (0, _objectWithoutProperties3.default)(_ref, ['SuperClass']);

  var ExhaustivePaginatedFetcher = function (_SuperClass) {
    (0, _inherits3.default)(ExhaustivePaginatedFetcher, _SuperClass);

    function ExhaustivePaginatedFetcher() {
      (0, _classCallCheck3.default)(this, ExhaustivePaginatedFetcher);
      return (0, _possibleConstructorReturn3.default)(this, (ExhaustivePaginatedFetcher.__proto__ || Object.getPrototypeOf(ExhaustivePaginatedFetcher)).apply(this, arguments));
    }

    (0, _createClass3.default)(ExhaustivePaginatedFetcher, [{
      key: 'combinePages',
      value: function combinePages(pages) {
        return pages.reduce(function (accumulator, page) {
          return [].concat((0, _toConsumableArray3.default)(accumulator), (0, _toConsumableArray3.default)(page));
        }, []);
      }
    }, {
      key: 'get',
      value: function () {
        var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(url) {
          var _this2 = this;

          var additionalParams = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
          var params, totalItems, itemsPerPage;
          return _regenerator2.default.wrap(function _callee$(_context) {
            while (1) {
              switch (_context.prev = _context.next) {
                case 0:
                  params = {
                    method: 'GET',
                    headers: (0, _get3.default)(ExhaustivePaginatedFetcher.prototype.__proto__ || Object.getPrototypeOf(ExhaustivePaginatedFetcher.prototype), 'callHeaders', this).call(this)
                  };
                  totalItems = void 0, itemsPerPage = void 0;

                  // manually fetch the first page, then get all remaining
                  // once we know the total number of pages (if there are any)

                  return _context.abrupt('return', (0, _get3.default)(ExhaustivePaginatedFetcher.prototype.__proto__ || Object.getPrototypeOf(ExhaustivePaginatedFetcher.prototype), 'fetch', this).call(this, (0, _get3.default)(ExhaustivePaginatedFetcher.prototype.__proto__ || Object.getPrototypeOf(ExhaustivePaginatedFetcher.prototype), 'appendQueryParams', this).call(this, url, additionalParams), params).then(function (response) {
                    // analyze properties of the first page response
                    // before getting its json body
                    totalItems = parseInt(response.headers.get('total'), 10);
                    itemsPerPage = parseInt(response.headers.get('per-page'), 10);
                    return response.json();
                  }).then(function (initial) {
                    if (totalItems > itemsPerPage) {
                      // create an array of page numbers, and use it to generate an array of
                      // get calls to the same url, but with different page numbers
                      var pageCount = Math.ceil(totalItems / itemsPerPage) - 1;
                      var pages = [].concat((0, _toConsumableArray3.default)(Array(pageCount).keys())).map(function (p) {
                        return (0, _get3.default)(ExhaustivePaginatedFetcher.prototype.__proto__ || Object.getPrototypeOf(ExhaustivePaginatedFetcher.prototype), 'get', _this2).call(_this2, url, Object.assign({}, additionalParams, { page: p + 2, per_page: itemsPerPage }));
                      });
                      return Promise.all(pages).then(function (pageResponses) {
                        return [].concat((0, _toConsumableArray3.default)(initial), (0, _toConsumableArray3.default)(_this2.combinePages(pageResponses)));
                      });
                    } else {
                      return initial;
                    }
                  }));

                case 3:
                case 'end':
                  return _context.stop();
              }
            }
          }, _callee, this);
        }));

        function get(_x2) {
          return _ref2.apply(this, arguments);
        }

        return get;
      }()
    }]);
    return ExhaustivePaginatedFetcher;
  }(SuperClass);

  return new ExhaustivePaginatedFetcher(args);
};

exports.default = ExhaustivePaginatedFetcher;