'use strict';

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

var _regenerator;

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

var getComponentStatus = function () {
  var _ref4 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee2(consumer, component, version) {
    var componentModel, existingBitMapId, currentlyUsedVersion, baseComponent, isModified, mergeResults, currentComponent, versionRef, componentVersion, newId;
    return (_regenerator || _load_regenerator()).default.wrap(function _callee2$(_context2) {
      while (1) {
        switch (_context2.prev = _context2.next) {
          case 0:
            _context2.next = 2;
            return consumer.scope.getModelComponentIfExist(component.id);

          case 2:
            componentModel = _context2.sent;

            if (componentModel) {
              _context2.next = 5;
              break;
            }

            throw new (_generalError || _load_generalError()).default(`component ${component.id.toString()} doesn't have any version yet`);

          case 5:
            if (componentModel.hasVersion(version)) {
              _context2.next = 7;
              break;
            }

            throw new (_generalError || _load_generalError()).default(`component ${component.id.toStringWithoutVersion()} doesn't have version ${version}`);

          case 7:
            existingBitMapId = consumer.bitMap.getExistingComponentId(component.id.toStringWithoutVersion());
            currentlyUsedVersion = (_bitId || _load_bitId()).BitId.parse(existingBitMapId).version;

            if (!(currentlyUsedVersion === version)) {
              _context2.next = 11;
              break;
            }

            throw new (_generalError || _load_generalError()).default(`component ${component.id.toStringWithoutVersion()} is already at version ${version}`);

          case 11:
            _context2.next = 13;
            return componentModel.loadVersion(currentlyUsedVersion, consumer.scope.objects);

          case 13:
            baseComponent = _context2.sent;
            _context2.next = 16;
            return consumer.isComponentModified(baseComponent, component);

          case 16:
            isModified = _context2.sent;
            mergeResults = void 0;

            if (!isModified) {
              _context2.next = 25;
              break;
            }

            _context2.next = 21;
            return componentModel.loadVersion(version, consumer.scope.objects);

          case 21:
            currentComponent = _context2.sent;
            _context2.next = 24;
            return (0, (_mergeVersion || _load_mergeVersion()).threeWayMerge)({
              consumer,
              otherComponent: component,
              otherVersion: currentlyUsedVersion,
              currentComponent,
              currentVersion: version,
              baseComponent
            });

          case 24:
            mergeResults = _context2.sent;

          case 25:
            versionRef = componentModel.versions[version];
            _context2.next = 28;
            return consumer.scope.getObject(versionRef.hash);

          case 28:
            componentVersion = _context2.sent;
            newId = component.id.clone();

            newId.version = version;
            return _context2.abrupt('return', { componentFromFS: component, componentFromModel: componentVersion, id: newId, mergeResults });

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

  return function getComponentStatus(_x3, _x4, _x5) {
    return _ref4.apply(this, arguments);
  };
}();

/**
 * 1) when the files are modified with conflicts and the strategy is "ours", leave the FS as is
 * and update only bitmap id version. (not the componentMap object).
 *
 * 2) when the files are modified with conflicts and the strategy is "theirs", write the component
 * according to id.version.
 *
 * 3) when files are modified with no conflict or files are modified with conflicts and the
 * strategy is manual, load the component according to id.version and update component.files.
 * applyModifiedVersion() docs explains what files are updated/added.
 *
 * Side note:
 * Deleted file => if files are in used version but not in the modified one, no need to delete it. (similar to git).
 * Added file => if files are not in used version but in the modified one, they'll be under mergeResults.addFiles
 */


var applyVersion = function () {
  var _ref5 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee4(consumer, id, componentFromFS, mergeResults, checkoutProps) {
    var _this = this;

    var mergeStrategy, verbose, skipNpmInstall, ignoreDist, filesStatus, componentsWithDependencies, componentWithDependencies, componentMap, rootDir, shouldWritePackageJson, shouldInstallNpmPackages, writePackageJson, files, modifiedStatus, filesStatusNoSharedDir, modifiedStatusNoSharedDir;
    return (_regenerator || _load_regenerator()).default.wrap(function _callee4$(_context4) {
      while (1) {
        switch (_context4.prev = _context4.next) {
          case 0:
            mergeStrategy = checkoutProps.mergeStrategy, verbose = checkoutProps.verbose, skipNpmInstall = checkoutProps.skipNpmInstall, ignoreDist = checkoutProps.ignoreDist;
            filesStatus = {};

            if (!(mergeResults && mergeResults.hasConflicts && mergeStrategy === (_mergeVersion || _load_mergeVersion()).MergeOptions.ours)) {
              _context4.next = 7;
              break;
            }

            componentFromFS.files.forEach(function (file) {
              filesStatus[(0, (_path2 || _load_path2()).pathNormalizeToLinux)(file.relative)] = (_mergeVersion || _load_mergeVersion()).FileStatus.unchanged;
            });
            consumer.bitMap.updateComponentId(id);
            consumer.bitMap.hasChanged = true;
            return _context4.abrupt('return', { id, filesStatus });

          case 7:
            _context4.next = 9;
            return consumer.scope.getMany([id]);

          case 9:
            componentsWithDependencies = _context4.sent;
            componentWithDependencies = componentsWithDependencies[0];
            componentMap = componentFromFS.componentMap;

            if (componentMap) {
              _context4.next = 14;
              break;
            }

            throw new (_generalError || _load_generalError()).default('applyVersion: componentMap was not found');

          case 14:
            if (componentMap.origin === (_constants || _load_constants()).COMPONENT_ORIGINS.AUTHORED && !id.scope) {
              componentWithDependencies.dependencies = [];
              componentWithDependencies.devDependencies = [];
              componentWithDependencies.allDependencies = [];
            }
            rootDir = componentMap.rootDir;

            shouldWritePackageJson = function () {
              var _ref6 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee3() {
                var packageJsonPath;
                return (_regenerator || _load_regenerator()).default.wrap(function _callee3$(_context3) {
                  while (1) {
                    switch (_context3.prev = _context3.next) {
                      case 0:
                        if (rootDir) {
                          _context3.next = 2;
                          break;
                        }

                        return _context3.abrupt('return', false);

                      case 2:
                        packageJsonPath = (_path || _load_path()).default.join(consumer.getPath(), rootDir, 'package.json');
                        return _context3.abrupt('return', (_fsExtra || _load_fsExtra()).default.exists(packageJsonPath));

                      case 4:
                      case 'end':
                        return _context3.stop();
                    }
                  }
                }, _callee3, _this);
              }));

              return function shouldWritePackageJson() {
                return _ref6.apply(this, arguments);
              };
            }();

            shouldInstallNpmPackages = function shouldInstallNpmPackages() {
              if (componentMap.origin === (_constants || _load_constants()).COMPONENT_ORIGINS.AUTHORED) return false;
              return !skipNpmInstall;
            };

            _context4.next = 20;
            return shouldWritePackageJson();

          case 20:
            writePackageJson = _context4.sent;
            files = componentWithDependencies.component.files;

            files.forEach(function (file) {
              filesStatus[(0, (_path2 || _load_path2()).pathNormalizeToLinux)(file.relative)] = (_mergeVersion || _load_mergeVersion()).FileStatus.updated;
            });

            modifiedStatus = {};

            if (!mergeResults) {
              _context4.next = 28;
              break;
            }

            _context4.next = 27;
            return applyModifiedVersion(files, mergeResults, mergeStrategy);

          case 27:
            modifiedStatus = _context4.sent;

          case 28:
            _context4.next = 30;
            return (0, (_writeComponents || _load_writeComponents()).default)({
              consumer,
              componentsWithDependencies,
              installNpmPackages: shouldInstallNpmPackages(),
              override: true,
              writeBitJson: !!componentFromFS.bitJson, // write bit.json only if it was there before
              verbose,
              writeDists: !ignoreDist,
              writePackageJson
            });

          case 30:
            filesStatusNoSharedDir = (0, (_mergeVersion || _load_mergeVersion()).filesStatusWithoutSharedDir)(filesStatus, componentWithDependencies.component, componentMap);
            modifiedStatusNoSharedDir = (0, (_mergeVersion || _load_mergeVersion()).filesStatusWithoutSharedDir)(modifiedStatus, componentWithDependencies.component, componentMap);
            return _context4.abrupt('return', { id, filesStatus: Object.assign(filesStatusNoSharedDir, modifiedStatusNoSharedDir) });

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

  return function applyVersion(_x6, _x7, _x8, _x9, _x10) {
    return _ref5.apply(this, arguments);
  };
}();

/**
 * relevant only when
 * 1) there is no conflict => add files from mergeResults: addFiles, overrideFiles and modifiedFiles.output.
 * 2) there is conflict and mergeStrategy is manual => add files from mergeResults: addFiles, overrideFiles and modifiedFiles.conflict.
 */


var applyModifiedVersion = exports.applyModifiedVersion = function () {
  var _ref7 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee8(componentFiles, mergeResults, mergeStrategy) {
    var _this2 = this;

    var filesStatus, modifiedP, addFilesP, overrideFilesP;
    return (_regenerator || _load_regenerator()).default.wrap(function _callee8$(_context8) {
      while (1) {
        switch (_context8.prev = _context8.next) {
          case 0:
            filesStatus = {};

            if (!(mergeResults.hasConflicts && mergeStrategy !== (_mergeVersion || _load_mergeVersion()).MergeOptions.manual)) {
              _context8.next = 3;
              break;
            }

            return _context8.abrupt('return', filesStatus);

          case 3:
            modifiedP = mergeResults.modifiedFiles.map(function () {
              var _ref8 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee5(file) {
                var filePath, foundFile;
                return (_regenerator || _load_regenerator()).default.wrap(function _callee5$(_context5) {
                  while (1) {
                    switch (_context5.prev = _context5.next) {
                      case 0:
                        filePath = (_path || _load_path()).default.normalize(file.filePath);
                        foundFile = componentFiles.find(function (componentFile) {
                          return componentFile.relative === filePath;
                        });

                        if (foundFile) {
                          _context5.next = 4;
                          break;
                        }

                        throw new (_generalError || _load_generalError()).default(`file ${filePath} not found`);

                      case 4:
                        if (!file.conflict) {
                          _context5.next = 9;
                          break;
                        }

                        foundFile.contents = Buffer.from(file.conflict);
                        filesStatus[file.filePath] = (_mergeVersion || _load_mergeVersion()).FileStatus.manual;
                        _context5.next = 15;
                        break;

                      case 9:
                        if (!file.output) {
                          _context5.next = 14;
                          break;
                        }

                        foundFile.contents = Buffer.from(file.output);
                        filesStatus[file.filePath] = (_mergeVersion || _load_mergeVersion()).FileStatus.merged;
                        _context5.next = 15;
                        break;

                      case 14:
                        throw new (_generalError || _load_generalError()).default('file does not have output nor conflict');

                      case 15:
                      case 'end':
                        return _context5.stop();
                    }
                  }
                }, _callee5, _this2);
              }));

              return function (_x14) {
                return _ref8.apply(this, arguments);
              };
            }());
            addFilesP = mergeResults.addFiles.map(function () {
              var _ref9 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee6(file) {
                return (_regenerator || _load_regenerator()).default.wrap(function _callee6$(_context6) {
                  while (1) {
                    switch (_context6.prev = _context6.next) {
                      case 0:
                        componentFiles.push(file.fsFile);
                        filesStatus[file.filePath] = (_mergeVersion || _load_mergeVersion()).FileStatus.added;

                      case 2:
                      case 'end':
                        return _context6.stop();
                    }
                  }
                }, _callee6, _this2);
              }));

              return function (_x15) {
                return _ref9.apply(this, arguments);
              };
            }());
            overrideFilesP = mergeResults.overrideFiles.map(function () {
              var _ref10 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee7(file) {
                var filePath, foundFile;
                return (_regenerator || _load_regenerator()).default.wrap(function _callee7$(_context7) {
                  while (1) {
                    switch (_context7.prev = _context7.next) {
                      case 0:
                        filePath = (_path || _load_path()).default.normalize(file.filePath);
                        foundFile = componentFiles.find(function (componentFile) {
                          return componentFile.relative === filePath;
                        });

                        if (foundFile) {
                          _context7.next = 4;
                          break;
                        }

                        throw new (_generalError || _load_generalError()).default(`file ${filePath} not found`);

                      case 4:
                        foundFile.contents = file.fsFile.contents;
                        filesStatus[file.filePath] = (_mergeVersion || _load_mergeVersion()).FileStatus.overridden;

                      case 6:
                      case 'end':
                        return _context7.stop();
                    }
                  }
                }, _callee7, _this2);
              }));

              return function (_x16) {
                return _ref10.apply(this, arguments);
              };
            }());
            _context8.next = 8;
            return Promise.all([Promise.all(modifiedP), Promise.all(addFilesP), Promise.all(overrideFilesP)]);

          case 8:
            return _context8.abrupt('return', filesStatus);

          case 9:
          case 'end':
            return _context8.stop();
        }
      }
    }, _callee8, this);
  }));

  return function applyModifiedVersion(_x11, _x12, _x13) {
    return _ref7.apply(this, arguments);
  };
}();

var _path;

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

var _fsExtra;

function _load_fsExtra() {
  return _fsExtra = _interopRequireDefault(require('fs-extra'));
}

var _bitId;

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

var _;

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

var _component;

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

var _constants;

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

var _path2;

function _load_path2() {
  return _path2 = require('../../utils/path');
}

var _version;

function _load_version() {
  return _version = _interopRequireDefault(require('../../scope/models/version'));
}

var _sources;

function _load_sources() {
  return _sources = require('../component/sources');
}

var _mergeVersion;

function _load_mergeVersion() {
  return _mergeVersion = require('./merge-version');
}

var _generalError;

function _load_generalError() {
  return _generalError = _interopRequireDefault(require('../../error/general-error'));
}

var _writeComponents;

function _load_writeComponents() {
  return _writeComponents = _interopRequireDefault(require('../component-ops/write-components'));
}

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"); }); }; }

exports.default = function () {
  var _ref = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee(consumer, checkoutProps) {
    var version, ids, promptMergeOptions, _ref2, components, allComponentsP, allComponents, componentWithConflict, componentsResultsP, componentsResults;

    return (_regenerator || _load_regenerator()).default.wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            version = checkoutProps.version, ids = checkoutProps.ids, promptMergeOptions = checkoutProps.promptMergeOptions;
            _context.next = 3;
            return consumer.loadComponents(ids);

          case 3:
            _ref2 = _context.sent;
            components = _ref2.components;
            allComponentsP = components.map(function (component) {
              return getComponentStatus(consumer, component, version);
            });
            _context.next = 8;
            return Promise.all(allComponentsP);

          case 8:
            allComponents = _context.sent;
            componentWithConflict = allComponents.find(function (component) {
              return component.mergeResults && component.mergeResults.hasConflicts;
            });

            if (!componentWithConflict) {
              _context.next = 17;
              break;
            }

            if (!(!promptMergeOptions && !checkoutProps.mergeStrategy)) {
              _context.next = 13;
              break;
            }

            throw new (_generalError || _load_generalError()).default(`automatic merge has failed for component ${componentWithConflict.id.toStringWithoutVersion()}.\nplease use "--manual" to manually merge changes or use "--theirs / --ours" to choose one of the conflicted versions`);

          case 13:
            if (checkoutProps.mergeStrategy) {
              _context.next = 17;
              break;
            }

            _context.next = 16;
            return (0, (_mergeVersion || _load_mergeVersion()).getMergeStrategyInteractive)();

          case 16:
            checkoutProps.mergeStrategy = _context.sent;

          case 17:
            componentsResultsP = allComponents.map(function (_ref3) {
              var id = _ref3.id,
                  componentFromFS = _ref3.componentFromFS,
                  mergeResults = _ref3.mergeResults;

              return applyVersion(consumer, id, componentFromFS, mergeResults, checkoutProps);
            });
            _context.next = 20;
            return Promise.all(componentsResultsP);

          case 20:
            componentsResults = _context.sent;
            return _context.abrupt('return', { components: componentsResults, version });

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

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

  return checkoutVersion;
}();