'use strict';

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

var _regenerator;

function _load_regenerator() {
  return _regenerator = _interopRequireDefault(require('babel-runtime/regenerator'));
}

var _bluebird;

function _load_bluebird() {
  return _bluebird = require('bluebird');
}

var _createClass = 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _path;

function _load_path() {
  return _path = _interopRequireDefault(require('path'));
}

var _pMapSeries;

function _load_pMapSeries() {
  return _pMapSeries = _interopRequireDefault(require('p-map-series'));
}

var _bitId;

function _load_bitId() {
  return _bitId = require('../../bit-id');
}

var _logger;

function _load_logger() {
  return _logger = _interopRequireDefault(require('../../logger/logger'));
}

var _consumerComponent;

function _load_consumerComponent() {
  return _consumerComponent = _interopRequireDefault(require('./consumer-component'));
}

var _utils;

function _load_utils() {
  return _utils = require('../../utils');
}

var _constants;

function _load_constants() {
  return _constants = require('../../constants');
}

var _dependencyResolver;

function _load_dependencyResolver() {
  return _dependencyResolver = require('./dependencies/dependency-resolver');
}

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

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var ComponentLoader = function () {
  // cache loaded components
  function ComponentLoader(consumer) {
    _classCallCheck(this, ComponentLoader);

    this._componentsCache = {};

    this.consumer = consumer;
    this.cacheResolvedDependencies = {};
  }

  _createClass(ComponentLoader, [{
    key: 'loadMany',
    value: function () {
      var _ref = (0, (_bluebird || _load_bluebird()).coroutine)( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee2(ids) {
        var _this = this;

        var throwOnFailure = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
        var alreadyLoadedComponents, idsToProcess, invalidComponents, driverExists, allComponents;
        return (_regenerator || _load_regenerator()).default.wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                (_logger || _load_logger()).default.debugAndAddBreadCrumb('ComponentLoader', 'loading consumer-components from the file-system, ids: {ids}', {
                  ids: ids.toString()
                });
                alreadyLoadedComponents = [];
                idsToProcess = [];
                invalidComponents = [];

                ids.forEach(function (id) {
                  if (!(id instanceof (_bitId || _load_bitId()).BitId)) {
                    throw new TypeError(`consumer.loadComponents expects to get BitId instances, instead, got "${typeof id}"`);
                  }
                  var idWithVersion = (0, (_utils || _load_utils()).getLatestVersionNumber)(_this.consumer.bitmapIds, id);
                  var idStr = idWithVersion.toString();
                  if (_this._componentsCache[idStr]) {
                    (_logger || _load_logger()).default.debugAndAddBreadCrumb('ComponentLoader', 'the component {idStr} has been already loaded, use the cached component', { idStr });
                    alreadyLoadedComponents.push(_this._componentsCache[idStr]);
                  } else {
                    idsToProcess.push(idWithVersion);
                  }
                });

                if (idsToProcess.length) {
                  _context2.next = 7;
                  break;
                }

                return _context2.abrupt('return', { components: alreadyLoadedComponents, invalidComponents });

              case 7:
                driverExists = this.consumer.warnForMissingDriver('Warning: Bit is not be able calculate the dependencies tree. Please install bit-{lang} driver and run tag again.');
                allComponents = [];
                _context2.next = 11;
                return (0, (_pMapSeries || _load_pMapSeries()).default)(idsToProcess, function () {
                  var _ref2 = (0, (_bluebird || _load_bluebird()).coroutine)( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee(id) {
                    var component;
                    return (_regenerator || _load_regenerator()).default.wrap(function _callee$(_context) {
                      while (1) {
                        switch (_context.prev = _context.next) {
                          case 0:
                            _context.next = 2;
                            return _this.loadOne(id, throwOnFailure, driverExists, invalidComponents);

                          case 2:
                            component = _context.sent;

                            if (component) {
                              _this._componentsCache[component.id.toString()] = component;
                              (_logger || _load_logger()).default.debugAndAddBreadCrumb('ComponentLoader', 'Finished loading the component "{id}"', {
                                id: component.id.toString()
                              });
                              allComponents.push(component);
                            }

                          case 4:
                          case 'end':
                            return _context.stop();
                        }
                      }
                    }, _callee, _this);
                  }));

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

              case 11:
                return _context2.abrupt('return', { components: allComponents.concat(alreadyLoadedComponents), invalidComponents });

              case 12:
              case 'end':
                return _context2.stop();
            }
          }
        }, _callee2, this);
      }));

      function loadMany(_x) {
        return _ref.apply(this, arguments);
      }

      return loadMany;
    }()
  }, {
    key: 'loadOne',
    value: function () {
      var _ref3 = (0, (_bluebird || _load_bluebird()).coroutine)( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee4(id, throwOnFailure, driverExists, invalidComponents) {
        var _this2 = this;

        var componentMap, bitDir, componentFromModel, component, loadDependencies;
        return (_regenerator || _load_regenerator()).default.wrap(function _callee4$(_context4) {
          while (1) {
            switch (_context4.prev = _context4.next) {
              case 0:
                componentMap = this.consumer.bitMap.getComponent(id);
                bitDir = this.consumer.getPath();

                if (componentMap.rootDir) {
                  bitDir = (_path || _load_path()).default.join(bitDir, componentMap.rootDir);
                }
                _context4.next = 5;
                return this.consumer.loadComponentFromModelIfExist(id);

              case 5:
                componentFromModel = _context4.sent;
                component = void 0;
                _context4.prev = 7;
                _context4.next = 10;
                return (_consumerComponent || _load_consumerComponent()).default.loadFromFileSystem({
                  bitDir,
                  componentMap,
                  id,
                  consumer: this.consumer,
                  componentFromModel
                });

              case 10:
                component = _context4.sent;
                _context4.next = 22;
                break;

              case 13:
                _context4.prev = 13;
                _context4.t0 = _context4['catch'](7);

                if (!throwOnFailure) {
                  _context4.next = 17;
                  break;
                }

                throw _context4.t0;

              case 17:

                (_logger || _load_logger()).default.errorAndAddBreadCrumb('component-loader.loadOne', 'failed loading {id} from the file-system', {
                  id: id.toString()
                });

                if (!(_consumerComponent || _load_consumerComponent()).default.isComponentInvalidByErrorType(_context4.t0)) {
                  _context4.next = 21;
                  break;
                }

                invalidComponents.push({ id, error: _context4.t0 });
                return _context4.abrupt('return', null);

              case 21:
                throw _context4.t0;

              case 22:

                component.loadedFromFileSystem = true;
                component.originallySharedDir = componentMap.originallySharedDir || null;
                component.wrapDir = componentMap.wrapDir || null;
                // reload component map as it may be changed after calling Component.loadFromFileSystem()
                component.componentMap = this.consumer.bitMap.getComponent(id);
                component.componentFromModel = componentFromModel;

                if (!(!driverExists || componentMap.origin === (_constants || _load_constants()).COMPONENT_ORIGINS.NESTED)) {
                  _context4.next = 29;
                  break;
                }

                return _context4.abrupt('return', component);

              case 29:
                loadDependencies = function () {
                  var _ref4 = (0, (_bluebird || _load_bluebird()).coroutine)( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee3() {
                    var dependencyResolver;
                    return (_regenerator || _load_regenerator()).default.wrap(function _callee3$(_context3) {
                      while (1) {
                        switch (_context3.prev = _context3.next) {
                          case 0:
                            dependencyResolver = new (_dependencyResolver || _load_dependencyResolver()).DependencyResolver(component, _this2.consumer, id);
                            _context3.next = 3;
                            return dependencyResolver.loadDependenciesForComponent(bitDir, _this2.cacheResolvedDependencies);

                          case 3:
                            _context3.next = 5;
                            return (0, (_dependencyResolver || _load_dependencyResolver()).updateDependenciesVersions)(_this2.consumer, component);

                          case 5:
                          case 'end':
                            return _context3.stop();
                        }
                      }
                    }, _callee3, _this2);
                  }));

                  return function loadDependencies() {
                    return _ref4.apply(this, arguments);
                  };
                }();

                _context4.next = 32;
                return loadDependencies();

              case 32:
                return _context4.abrupt('return', component);

              case 33:
              case 'end':
                return _context4.stop();
            }
          }
        }, _callee4, this, [[7, 13]]);
      }));

      function loadOne(_x4, _x5, _x6, _x7) {
        return _ref3.apply(this, arguments);
      }

      return loadOne;
    }()
  }], [{
    key: 'getInstance',
    value: function getInstance(consumer) {
      return new ComponentLoader(consumer);
    }
  }]);

  return ComponentLoader;
}();

exports.default = ComponentLoader;