'use strict';

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

var _regenerator;

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

var _path;

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

var _ramda;

function _load_ramda() {
  return _ramda = _interopRequireDefault(require('ramda'));
}

var _semver;

function _load_semver() {
  return _semver = _interopRequireDefault(require('semver'));
}

var _componentMap;

function _load_componentMap() {
  return _componentMap = _interopRequireDefault(require('../../../bit-map/component-map'));
}

var _bitId;

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

var _component;

function _load_component() {
  return _component = _interopRequireDefault(require('../../../component'));
}

var _logger;

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

var _consumer;

function _load_consumer() {
  return _consumer = require('../../../../consumer');
}

var _bitJson;

function _load_bitJson() {
  return _bitJson = _interopRequireDefault(require('../../../bit-json'));
}

var _dependencies;

function _load_dependencies() {
  return _dependencies = _interopRequireDefault(require('../dependencies'));
}

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 getIdFromModelDeps(componentFromModel, componentId) {
  if (!componentFromModel) return null;
  var id = componentFromModel.getAllDependencies().find(function (dep) {
    return dep.id.toStringWithoutVersion() === componentId.toStringWithoutVersion();
  });
  if (!id) return null;
  return id.id.toString();
}

function getIdFromBitJson(bitJson, componentId) {
  var getVersion = function getVersion() {
    if (!bitJson) return null;
    if (!bitJson.dependencies && !bitJson.devDependencies) return null;
    if (bitJson.dependencies[componentId.toStringWithoutVersion()]) {
      return bitJson.dependencies[componentId.toStringWithoutVersion()];
    }
    if (bitJson.devDependencies) {
      return bitJson.devDependencies[componentId.toStringWithoutVersion()];
    }
    return null;
  };
  var version = getVersion();
  if (!version) return null;
  componentId.version = version;
  return componentId.toString();
}

/**
 * the logic of finding the dependency version in the package.json is mostly done in the driver
 * resolveNodePackage method.
 * it first searches in the dependent package.json and propagate up to the consumer root, if not
 * found it goes to the dependency package.json.
 */
function getIdFromPackageJson(consumer, component, componentId) {
  if (!componentId.scope) return null;
  var rootDir = component.componentMap.rootDir;
  var consumerPath = consumer.getPath();
  var basePath = rootDir ? (_path || _load_path()).default.join(consumerPath, rootDir) : consumerPath;
  var packagePath = (_consumer || _load_consumer()).Consumer.getNodeModulesPathOfComponent(component.bindingPrefix, componentId);
  var packageName = packagePath.replace(`node_modules${(_path || _load_path()).default.sep}`, '');
  var modulePath = consumer.driver.driver.resolveModulePath(packageName, basePath, consumerPath);
  if (!modulePath) return null; // e.g. it's author and wasn't exported yet, so there's no node_modules of that component
  var packageObject = consumer.driver.driver.resolveNodePackage(basePath, modulePath);
  if (!packageObject || (_ramda || _load_ramda()).default.isEmpty(packageObject)) return null;
  var packageId = Object.keys(packageObject)[0];
  var version = packageObject[packageId];
  if (!(_semver || _load_semver()).default.valid(version)) return null; // it's probably a relative path to the component
  componentId.version = version.replace(/[^0-9.]/g, ''); // allow only numbers and dots to get an exact version
  return componentId.toString();
}

function getIdFromBitMap(consumer, component, componentId) {
  var componentMap = component.componentMap;
  if (componentMap.dependencies && !(_ramda || _load_ramda()).default.isEmpty(componentMap.dependencies)) {
    var dependencyId = componentMap.dependencies.find(function (dependency) {
      return (_bitId || _load_bitId()).BitId.getStringWithoutVersion(dependency) === componentId.toStringWithoutVersion();
    });
    if (dependencyId) return dependencyId;
  }
  return consumer.bitMap.getExistingComponentId(componentId.toStringWithoutVersion());
}

/**
 * The dependency version is determined by the following strategies by this order.
 * 1) if bit.json is different than the model, use bit.json
 * 2) if package.json is different than the model, use package.json. to find the package.json follow this steps:
 * 2 a) search in the component directory for package.json and look for dependencies or devDependencies with the name of the dependency
 * 2 b) if not found there, propagate until you reach the consumer root directory.
 * 2 c) if not found, go directly to the dependency directory and find the version in its package.json
 * 3) if bitmap has a version, use it.
 * 4) use the model if it has a version
 * 5) use the version from bit.json (regardless the status of the model)
 * 6) use the version from package.json (regardless the status of the model)
 *
 * cases where dependency version may be different than the model:
 * 1) user changed bit.json
 * 2) user changed package.json, either, manually or by npm-install —save.
 * 3) user updated a dependency with npm without —save.
 * 4) user imported the dependency with different version causing the bitmap to change.
 */

exports.default = function () {
  var _ref = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee2(consumer, component) {
    var _this = this;

    var updateDependencies;
    return (_regenerator || _load_regenerator()).default.wrap(function _callee2$(_context2) {
      while (1) {
        switch (_context2.prev = _context2.next) {
          case 0:
            updateDependencies = function () {
              var _ref2 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee(dependencies) {
                return (_regenerator || _load_regenerator()).default.wrap(function _callee$(_context) {
                  while (1) {
                    switch (_context.prev = _context.next) {
                      case 0:
                        dependencies.get().forEach(function (dependency) {
                          var id = dependency.id;
                          var idFromModel = getIdFromModelDeps(component.componentFromModel, id);
                          var idFromBitJson = getIdFromBitJson(component.bitJson, id);
                          var idFromPackageJson = getIdFromPackageJson(consumer, component, id);
                          var idFromBitMap = getIdFromBitMap(consumer, component, id);

                          // get from bitJson when it was changed from the model or when there is no model.
                          var getFromBitJsonIfChanged = function getFromBitJsonIfChanged() {
                            if (!idFromBitJson) return null;
                            if (!idFromModel) return idFromBitJson;
                            if (idFromBitJson !== idFromModel) return idFromBitJson;
                            return null;
                          };
                          // get from packageJson when it was changed from the model or when there is no model.
                          var getFromPackageJsonIfChanged = function getFromPackageJsonIfChanged() {
                            if (!idFromPackageJson) return null;
                            if (!idFromModel) return idFromPackageJson;
                            if (idFromPackageJson !== idFromModel) return idFromPackageJson;
                            return null;
                          };
                          var getFromBitMap = function getFromBitMap() {
                            if (idFromBitMap) return idFromBitMap;
                            return null;
                          };
                          var getFromModel = function getFromModel() {
                            if (idFromModel) return idFromModel;
                            return null;
                          };
                          var getFromBitJsonOrPackageJson = function getFromBitJsonOrPackageJson() {
                            if (idFromBitJson) return idFromBitJson;
                            if (idFromPackageJson) return idFromPackageJson;
                            return null;
                          };
                          var strategies = [getFromBitJsonIfChanged, getFromPackageJsonIfChanged, getFromBitMap, getFromModel, getFromBitJsonOrPackageJson];

                          var _iteratorNormalCompletion = true;
                          var _didIteratorError = false;
                          var _iteratorError = undefined;

                          try {
                            for (var _iterator = strategies[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
                              var strategy = _step.value;

                              var strategyId = strategy();
                              if (strategyId) {
                                dependency.id.version = (_bitId || _load_bitId()).BitId.parse(strategyId).version;
                                (_logger || _load_logger()).default.debug(`found dependency version ${dependency.id.toString()} in strategy ${strategy.name}`);
                                return;
                              }
                            }
                          } catch (err) {
                            _didIteratorError = true;
                            _iteratorError = err;
                          } finally {
                            try {
                              if (!_iteratorNormalCompletion && _iterator.return) {
                                _iterator.return();
                              }
                            } finally {
                              if (_didIteratorError) {
                                throw _iteratorError;
                              }
                            }
                          }
                        });

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

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

            updateDependencies(component.dependencies);
            updateDependencies(component.devDependencies);

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

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

  return updateDependenciesVersions;
}();