'use strict';

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

var _regenerator;

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

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 _bitId;

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

var _logger;

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

var _analytics;

function _load_analytics() {
  return _analytics = require('../../analytics/analytics');
}

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 _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }

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 = _asyncToGenerator( /*#__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, components, allComponents, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, componentP, component;

        return (_regenerator || _load_regenerator()).default.wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                (_logger || _load_logger()).default.debug(`loading consumer-components from the file-system, ids: ${ids.join(', ')}`);
                (_analytics || _load_analytics()).Analytics.addBreadCrumb('load components', `loading consumer-components from the file-system, ids: ${(_analytics || _load_analytics()).Analytics.hashData(ids)}`);
                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 idWithoutVersion = id.toStringWithoutVersion();
                  if (_this._componentsCache[idWithoutVersion]) {
                    (_logger || _load_logger()).default.debug(`the component ${idWithoutVersion} has been already loaded, use the cached component`);
                    (_analytics || _load_analytics()).Analytics.addBreadCrumb('load components', `the component ${(_analytics || _load_analytics()).Analytics.hashData(idWithoutVersion)} has been already loaded, use the cached component`);
                    alreadyLoadedComponents.push(_this._componentsCache[idWithoutVersion]);
                  } else {
                    idsToProcess.push(id);
                  }
                });

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

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

              case 8:
                driverExists = this.consumer.warnForMissingDriver('Warning: Bit is not be able calculate the dependencies tree. Please install bit-{lang} driver and run commit again.');
                components = idsToProcess.map(function () {
                  var _ref2 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee(id) {
                    return (_regenerator || _load_regenerator()).default.wrap(function _callee$(_context) {
                      while (1) {
                        switch (_context.prev = _context.next) {
                          case 0:
                            return _context.abrupt('return', _this.loadOne(id, throwOnFailure, driverExists, invalidComponents));

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

                  return function (_x3) {
                    return _ref2.apply(this, arguments);
                  };
                }());
                allComponents = [];
                _iteratorNormalCompletion = true;
                _didIteratorError = false;
                _iteratorError = undefined;
                _context2.prev = 14;
                _iterator = components[Symbol.iterator]();

              case 16:
                if (_iteratorNormalCompletion = (_step = _iterator.next()).done) {
                  _context2.next = 25;
                  break;
                }

                componentP = _step.value;
                _context2.next = 20;
                return componentP;

              case 20:
                component = _context2.sent;
                // eslint-disable-line no-await-in-loop
                if (component) {
                  this._componentsCache[component.id.toStringWithoutVersion()] = component;
                  (_logger || _load_logger()).default.debug(`Finished loading the component, ${component.id.toString()}`);
                  (_analytics || _load_analytics()).Analytics.addBreadCrumb('load components', `Finished loading the component, ${(_analytics || _load_analytics()).Analytics.hashData(component.id.toString())}`);
                  allComponents.push(component);
                }

              case 22:
                _iteratorNormalCompletion = true;
                _context2.next = 16;
                break;

              case 25:
                _context2.next = 31;
                break;

              case 27:
                _context2.prev = 27;
                _context2.t0 = _context2['catch'](14);
                _didIteratorError = true;
                _iteratorError = _context2.t0;

              case 31:
                _context2.prev = 31;
                _context2.prev = 32;

                if (!_iteratorNormalCompletion && _iterator.return) {
                  _iterator.return();
                }

              case 34:
                _context2.prev = 34;

                if (!_didIteratorError) {
                  _context2.next = 37;
                  break;
                }

                throw _iteratorError;

              case 37:
                return _context2.finish(34);

              case 38:
                return _context2.finish(31);

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

              case 40:
              case 'end':
                return _context2.stop();
            }
          }
        }, _callee2, this, [[14, 27, 31, 39], [32,, 34, 38]]);
      }));

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

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

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

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

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

              case 11:
                component = _context4.sent;
                _context4.next = 24;
                break;

              case 14:
                _context4.prev = 14;
                _context4.t0 = _context4['catch'](8);

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

                throw _context4.t0;

              case 18:

                (_logger || _load_logger()).default.error(`failed loading ${id.toString()} from the file-system`);
                (_analytics || _load_analytics()).Analytics.addBreadCrumb('load components', `failed loading ${(_analytics || _load_analytics()).Analytics.hashData(id.toString())} from the file-system`);

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

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

              case 23:
                throw _context4.t0;

              case 24:

                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(idWithConcreteVersion);
                component.componentFromModel = componentFromModel;

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

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

              case 31:
                loadDependencies = function () {
                  var _ref4 = _asyncToGenerator( /*#__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, idWithConcreteVersion);
                            _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 = 34;
                return loadDependencies();

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

              case 35:
              case 'end':
                return _context4.stop();
            }
          }
        }, _callee4, this, [[8, 14]]);
      }));

      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;