'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 _ramda;

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

var _;

function _load_() {
  return _ = require('./');
}

var _bitId;

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

var _scope;

function _load_scope() {
  return _scope = _interopRequireDefault(require('../../../scope/scope'));
}

var _bitMap;

function _load_bitMap() {
  return _bitMap = _interopRequireDefault(require('../../bit-map'));
}

var _utils;

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

var _validationError;

function _load_validationError() {
  return _validationError = _interopRequireDefault(require('../../../error/validation-error'));
}

var _validateType;

function _load_validateType() {
  return _validateType = _interopRequireDefault(require('../../../utils/validate-type'));
}

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 Dependencies = function () {
  function Dependencies() {
    var dependencies = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];

    _classCallCheck(this, Dependencies);

    this.dependencies = this.deserialize(dependencies);
  }

  _createClass(Dependencies, [{
    key: 'serialize',
    value: function serialize() {
      return this.dependencies.map(function (dep) {
        return Object.assign({}, dep, { id: dep.id.toString() });
      });
    }
  }, {
    key: 'get',
    value: function get() {
      return this.dependencies;
    }
  }, {
    key: 'getClone',
    value: function getClone() {
      return this.dependencies.map(function (dependency) {
        return (_ || _load_()).Dependency.getClone(dependency);
      });
    }
  }, {
    key: 'add',
    value: function add(dependency) {
      this.dependencies.push(dependency);
    }
  }, {
    key: 'deserialize',
    value: function deserialize(dependencies) {
      return dependencies.map(function (dependency) {
        return {
          id: (_ramda || _load_ramda()).default.is(String, dependency.id) ? (_bitId || _load_bitId()).BitId.parse(dependency.id) : dependency.id,
          relativePaths: dependency.relativePaths || [
          // backward compatibility. (previously, it was "relativePath" without the ending 's' and was not an array.
          { sourceRelativePath: dependency.relativePath, destinationRelativePath: dependency.relativePath }]
        };
      });
    }
  }, {
    key: 'toStringOfIds',
    value: function toStringOfIds() {
      return this.dependencies.map(function (dep) {
        return dep.id.toString();
      });
    }
  }, {
    key: 'isEmpty',
    value: function isEmpty() {
      return !this.dependencies.length;
    }
  }, {
    key: 'asWritableObject',
    value: function asWritableObject() {
      return (_ramda || _load_ramda()).default.mergeAll(this.dependencies.map(function (dependency) {
        return dependency.id.toObject();
      }));
    }
  }, {
    key: 'cloneAsString',
    value: function cloneAsString() {
      return this.dependencies.map(function (dependency) {
        var dependencyClone = (_ramda || _load_ramda()).default.clone(dependency);
        dependencyClone.id = dependency.id.toString();
        return dependencyClone;
      });
    }
  }, {
    key: 'stripOriginallySharedDir',
    value: function stripOriginallySharedDir(bitMap, originallySharedDir) {
      this.dependencies.forEach(function (dependency) {
        (_ || _load_()).Dependency.stripOriginallySharedDir(dependency, bitMap, originallySharedDir);
      });
    }

    /**
     * needed for calculating the originallySharedDir. when isCustomResolveUsed, don't take into
     * account the dependencies as they don't have relative paths
     */

  }, {
    key: 'getSourcesPaths',
    value: function getSourcesPaths() {
      return (_ramda || _load_ramda()).default.flatten(this.dependencies.map(function (dependency) {
        return dependency.relativePaths.map(function (relativePath) {
          return relativePath.isCustomResolveUsed ? null : relativePath.sourceRelativePath;
        }).filter(function (x) {
          return x;
        });
      }));
    }
  }, {
    key: 'getById',
    value: function getById(id) {
      return this.dependencies.find(function (dep) {
        return dep.id.toString() === id;
      });
    }
  }, {
    key: 'addRemoteAndLocalVersions',
    value: function () {
      var _ref = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee(scope, modelDependencies) {
        var dependenciesIds, localDependencies, remoteVersionsDependencies;
        return (_regenerator || _load_regenerator()).default.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                dependenciesIds = this.dependencies.map(function (dependency) {
                  return dependency.id;
                });
                _context.next = 3;
                return scope.latestVersions(dependenciesIds);

              case 3:
                localDependencies = _context.sent;
                _context.next = 6;
                return scope.fetchRemoteVersions(dependenciesIds);

              case 6:
                remoteVersionsDependencies = _context.sent;


                this.dependencies.forEach(function (dependency) {
                  var dependencyIdWithoutVersion = dependency.id.toStringWithoutVersion();
                  var remoteVersionId = remoteVersionsDependencies.find(function (remoteId) {
                    return remoteId.toStringWithoutVersion() === dependencyIdWithoutVersion;
                  });
                  var localVersionId = localDependencies.find(function (localId) {
                    return localId.toStringWithoutVersion() === dependencyIdWithoutVersion;
                  });
                  var modelVersionId = modelDependencies.get().find(function (modelDependency) {
                    return modelDependency.id.toStringWithoutVersion() === dependencyIdWithoutVersion;
                  });
                  dependency.remoteVersion = remoteVersionId ? remoteVersionId.version : null;
                  dependency.localVersion = localVersionId ? localVersionId.version : null;
                  dependency.currentVersion = modelVersionId ? modelVersionId.id.version : dependency.id.version;
                });

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

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

      return addRemoteAndLocalVersions;
    }()
  }, {
    key: 'getCustomResolvedData',
    value: function getCustomResolvedData() {
      var importSourceMap = {};
      this.dependencies.forEach(function (dependency) {
        dependency.relativePaths.forEach(function (relativePath) {
          if (relativePath.isCustomResolveUsed) {
            if (!relativePath.importSource) {
              throw new Error(`${dependency.id.toString()} relativePath.importSource must be set when relativePath.isCustomResolveUsed`);
            }
            importSourceMap[relativePath.importSource] = dependency.id;
          }
        });
      });
      return importSourceMap;
    }
  }, {
    key: 'validate',
    value: function validate() {
      var message = 'failed validating the dependencies.';
      (0, (_validateType || _load_validateType()).default)(message, this.dependencies, 'dependencies', 'array');
      this.dependencies.forEach(function (dependency) {
        (0, (_validateType || _load_validateType()).default)(message, dependency, 'dependency', 'object');
        if (!dependency.id) throw new (_validationError || _load_validationError()).default('one of the dependencies is missing ID');
        if (!dependency.relativePaths) {
          throw new (_validationError || _load_validationError()).default(`a dependency ${dependency.id.toString()} is missing relativePaths`);
        }
        var permittedProperties = ['id', 'relativePaths'];
        var currentProperties = Object.keys(dependency);
        currentProperties.forEach(function (currentProp) {
          if (!permittedProperties.includes(currentProp)) {
            throw new (_validationError || _load_validationError()).default(`a dependency ${dependency.id.toString()} has an undetected property "${currentProp}"`);
          }
        });
        (0, (_validateType || _load_validateType()).default)(message, dependency.relativePaths, 'dependency.relativePaths', 'array');
        dependency.relativePaths.forEach(function (relativePath) {
          message = `failed validating dependency ${dependency.id.toString()}.`;
          (0, (_validateType || _load_validateType()).default)(message, dependency, 'dependency', 'object');
          var requiredProps = ['sourceRelativePath', 'destinationRelativePath'];
          var pathProps = ['sourceRelativePath', 'destinationRelativePath'];
          var optionalProps = ['importSpecifiers', 'isCustomResolveUsed', 'importSource'];
          var allProps = requiredProps.concat(optionalProps);
          requiredProps.forEach(function (prop) {
            if (!relativePath[prop]) {
              throw new (_validationError || _load_validationError()).default(`${message} relativePaths.${prop} is missing`);
            }
          });
          pathProps.forEach(function (prop) {
            if (!(0, (_utils || _load_utils()).isValidPath)(relativePath[prop])) {
              throw new (_validationError || _load_validationError()).default(`${message} relativePaths.${prop} has an invalid path ${relativePath[prop]}`);
            }
          });
          Object.keys(relativePath).forEach(function (prop) {
            if (!allProps.includes(prop)) {
              throw new (_validationError || _load_validationError()).default(`${message} undetected property of relativePaths "${prop}"`);
            }
          });
          if (relativePath.isCustomResolveUsed) {
            if (!relativePath.importSource) {
              throw new (_validationError || _load_validationError()).default(`a dependency ${dependency.id.toString()} is missing relativePath.importSource`);
            }
            (0, (_validateType || _load_validateType()).default)(message, relativePath.importSource, 'relativePath.importSource', 'string');
          }
          if (relativePath.importSpecifiers) {
            (0, (_validateType || _load_validateType()).default)(message, relativePath.importSpecifiers, 'relativePath.importSpecifiers', 'array');
            relativePath.importSpecifiers.forEach(function (importSpecifier) {
              (0, (_validateType || _load_validateType()).default)(message, importSpecifier, 'importSpecifier', 'object');
              if (!importSpecifier.mainFile) {
                throw new (_validationError || _load_validationError()).default(`${message} mainFile property is missing from the importSpecifier`);
              }
              var specifierProps = ['isDefault', 'name'].sort().toString();
              var mainFileProps = Object.keys(importSpecifier.mainFile).sort().toString();
              if (mainFileProps !== specifierProps) {
                throw new (_validationError || _load_validationError()).default(`${message} expected properties of importSpecifier.mainFile "${specifierProps}", got "${mainFileProps}"`);
              }
              if (importSpecifier.linkFile) {
                var linkFileProps = Object.keys(importSpecifier.linkFile).sort().toString();
                if (linkFileProps !== specifierProps) {
                  throw new (_validationError || _load_validationError()).default(`${message} expected properties of importSpecifier.linkFile "${specifierProps}", got "${mainFileProps}"`);
                }
              }
              var specifierPermittedProps = ['mainFile', 'linkFile'];
              Object.keys(importSpecifier).forEach(function (prop) {
                if (!specifierPermittedProps.includes(prop)) {
                  throw new (_validationError || _load_validationError()).default(`${message} undetected property of importSpecifier "${prop}"`);
                }
              });
            });
          }
        });
      });
    }
  }]);

  return Dependencies;
}();

exports.default = Dependencies;