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

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

var _ramdaAdjunct;

function _load_ramdaAdjunct() {
  return _ramdaAdjunct = _interopRequireWildcard(require('ramda-adjunct'));
}

var _fsExtra;

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

var _bitId;

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

var _utils;

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

var _compilerExtension;

function _load_compilerExtension() {
  return _compilerExtension = _interopRequireDefault(require('../../extensions/compiler-extension'));
}

var _compilerExtension2;

function _load_compilerExtension2() {
  return _compilerExtension2 = require('../../extensions/compiler-extension');
}

var _testerExtension;

function _load_testerExtension() {
  return _testerExtension = _interopRequireDefault(require('../../extensions/tester-extension'));
}

var _testerExtension2;

function _load_testerExtension2() {
  return _testerExtension2 = require('../../extensions/tester-extension');
}

var _exceptions;

function _load_exceptions() {
  return _exceptions = require('./exceptions');
}

var _constants;

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

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }

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 AbstractBitJson = function () {
  function AbstractBitJson(props) {
    _classCallCheck(this, AbstractBitJson);

    this._compiler = props.compiler || {};
    this._tester = props.tester || {};
    this.dependencies = props.dependencies || (_constants || _load_constants()).DEFAULT_DEPENDENCIES;
    this.devDependencies = props.devDependencies || (_constants || _load_constants()).DEFAULT_DEPENDENCIES;
    this.compilerDependencies = props.compilerDependencies || (_constants || _load_constants()).DEFAULT_DEPENDENCIES;
    this.testerDependencies = props.testerDependencies || (_constants || _load_constants()).DEFAULT_DEPENDENCIES;
    this.lang = props.lang || (_constants || _load_constants()).DEFAULT_LANGUAGE;
    this.bindingPrefix = props.bindingPrefix || (_constants || _load_constants()).DEFAULT_BINDINGS_PREFIX;
    this.extensions = props.extensions || (_constants || _load_constants()).DEFAULT_EXTENSIONS;
  }

  _createClass(AbstractBitJson, [{
    key: 'addDependencies',
    value: function addDependencies(bitIds) {
      var idObjects = (_ramda || _load_ramda()).default.mergeAll(bitIds.map(function (bitId) {
        return bitId.toObject();
      }));
      this.dependencies = (_ramda || _load_ramda()).default.merge(this.dependencies, idObjects);
      return this;
    }
  }, {
    key: 'addDependency',
    value: function addDependency(bitId) {
      this.dependencies = (_ramda || _load_ramda()).default.merge(this.dependencies, bitId.toObject());
      return this;
    }
  }, {
    key: 'hasCompiler',
    value: function hasCompiler() {
      return !!this.compiler && this._compiler !== (_constants || _load_constants()).NO_PLUGIN_TYPE && !(_ramda || _load_ramda()).default.isEmpty(this.compiler);
    }
  }, {
    key: 'hasTester',
    value: function hasTester() {
      return !!this.tester && this._tester !== (_constants || _load_constants()).NO_PLUGIN_TYPE && !(_ramda || _load_ramda()).default.isEmpty(this.tester);
    }
  }, {
    key: 'getEnvsByType',
    value: function getEnvsByType(type) {
      if (type === (_compilerExtension2 || _load_compilerExtension2()).COMPILER_ENV_TYPE) {
        return this.compiler;
      }
      return this.tester;
    }
  }, {
    key: 'loadCompiler',
    value: function () {
      var _ref = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee(consumerPath, scopePath, context) {
        var compilerP, compiler;
        return (_regenerator || _load_regenerator()).default.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                if (this.hasCompiler()) {
                  _context.next = 2;
                  break;
                }

                return _context.abrupt('return', null);

              case 2:
                compilerP = this.loadEnv((_compilerExtension2 || _load_compilerExtension2()).COMPILER_ENV_TYPE, consumerPath, scopePath, (_compilerExtension || _load_compilerExtension()).default.load, context);
                _context.next = 5;
                return compilerP;

              case 5:
                compiler = _context.sent;
                return _context.abrupt('return', compiler);

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

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

      return loadCompiler;
    }()
  }, {
    key: 'loadTester',
    value: function () {
      var _ref2 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee2(consumerPath, scopePath, context) {
        var testerP, tester;
        return (_regenerator || _load_regenerator()).default.wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                if (this.hasTester()) {
                  _context2.next = 2;
                  break;
                }

                return _context2.abrupt('return', null);

              case 2:
                testerP = this.loadEnv((_testerExtension2 || _load_testerExtension2()).TESTER_ENV_TYPE, consumerPath, scopePath, (_testerExtension || _load_testerExtension()).default.load, context);
                _context2.next = 5;
                return testerP;

              case 5:
                tester = _context2.sent;
                return _context2.abrupt('return', tester);

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

      function loadTester(_x4, _x5, _x6) {
        return _ref2.apply(this, arguments);
      }

      return loadTester;
    }()
  }, {
    key: 'loadEnv',
    value: function () {
      var _ref3 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee3(envType, consumerPath, scopePath, loadFunc, context) {
        var envs, envName, envObject, envProps, env;
        return (_regenerator || _load_regenerator()).default.wrap(function _callee3$(_context3) {
          while (1) {
            switch (_context3.prev = _context3.next) {
              case 0:
                envs = this.getEnvsByType(envType);

                if (envs) {
                  _context3.next = 3;
                  break;
                }

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

              case 3:
                // TODO: Gilad - support more than one key of compiler
                envName = Object.keys(envs)[0];
                envObject = envs[envName];
                envProps = getEnvsProps(consumerPath, scopePath, envName, envObject, this.path, envType, context);
                _context3.next = 8;
                return loadFunc(envProps);

              case 8:
                env = _context3.sent;
                return _context3.abrupt('return', env);

              case 10:
              case 'end':
                return _context3.stop();
            }
          }
        }, _callee3, this);
      }));

      function loadEnv(_x7, _x8, _x9, _x10, _x11) {
        return _ref3.apply(this, arguments);
      }

      return loadEnv;
    }()

    /**
     * before v13, envs were strings of bit-id.
     * to be backward compatible, if an env doesn't have any files/config, convert it to a string
     */

  }, {
    key: 'getBackwardCompatibleEnv',
    value: function getBackwardCompatibleEnv(type) {
      var envObj = this.getEnvsByType(type);
      if (!envObj) return undefined;
      if (Object.keys(envObj).length !== 1) return envObj; // it has more than one id, it's >= v13
      var envId = Object.keys(envObj)[0];
      if ((_ramdaAdjunct || _load_ramdaAdjunct()).isNilOrEmpty(envObj[envId].rawConfig) && (_ramdaAdjunct || _load_ramdaAdjunct()).isNilOrEmpty(envObj[envId].options) && (_ramdaAdjunct || _load_ramdaAdjunct()).isNilOrEmpty(envObj[envId].files)) {
        return envId;
      }
      return envObj;
    }
  }, {
    key: 'getDependencies',
    value: function getDependencies() {
      return (_bitId || _load_bitId()).BitIds.fromObject(this.dependencies);
    }
  }, {
    key: 'toPlainObject',
    value: function toPlainObject() {
      var isPropDefaultOrNull = function isPropDefaultOrNull(val, key) {
        if (!val) return false;
        if (key === 'lang') return val !== (_constants || _load_constants()).DEFAULT_LANGUAGE;
        if (key === 'bindingPrefix') return val !== (_constants || _load_constants()).DEFAULT_BINDINGS_PREFIX;
        if (key === 'extensions') return !(_ramda || _load_ramda()).default.equals(val, (_constants || _load_constants()).DEFAULT_EXTENSIONS);
        return true;
      };

      return (0, (_utils || _load_utils()).filterObject)({
        lang: this.lang,
        bindingPrefix: this.bindingPrefix,
        env: {
          compiler: this.getBackwardCompatibleEnv((_compilerExtension2 || _load_compilerExtension2()).COMPILER_ENV_TYPE),
          tester: this.getBackwardCompatibleEnv((_testerExtension2 || _load_testerExtension2()).TESTER_ENV_TYPE)
        },
        dependencies: this.dependencies,
        extensions: this.extensions
      }, isPropDefaultOrNull);
    }
  }, {
    key: 'write',
    value: function () {
      var _ref5 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee4(_ref4) {
        var bitDir = _ref4.bitDir,
            _ref4$override = _ref4.override,
            override = _ref4$override === undefined ? true : _ref4$override,
            _ref4$throws = _ref4.throws,
            throws = _ref4$throws === undefined ? true : _ref4$throws;
        var isExisting, isBitDirExisting;
        return (_regenerator || _load_regenerator()).default.wrap(function _callee4$(_context4) {
          while (1) {
            switch (_context4.prev = _context4.next) {
              case 0:
                isExisting = false;
                _context4.next = 3;
                return (_fsExtra || _load_fsExtra()).default.exists(bitDir);

              case 3:
                isBitDirExisting = _context4.sent;

                if (!isBitDirExisting) {
                  _context4.next = 8;
                  break;
                }

                _context4.next = 7;
                return AbstractBitJson.hasExisting(bitDir);

              case 7:
                isExisting = _context4.sent;

              case 8:
                if (!(!override && isExisting)) {
                  _context4.next = 12;
                  break;
                }

                if (!throws) {
                  _context4.next = 11;
                  break;
                }

                throw new (_exceptions || _load_exceptions()).BitJsonAlreadyExists();

              case 11:
                return _context4.abrupt('return', false);

              case 12:
                return _context4.abrupt('return', (_fsExtra || _load_fsExtra()).default.outputJson(AbstractBitJson.composePath(bitDir), this.toPlainObject(), { spaces: 4 }));

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

      function write(_x12) {
        return _ref5.apply(this, arguments);
      }

      return write;
    }()
  }, {
    key: 'toJson',
    value: function toJson() {
      var readable = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;

      if (!readable) return JSON.stringify(this.toPlainObject());
      return JSON.stringify(this.toPlainObject(), null, 4);
    }
  }, {
    key: 'compiler',
    get: function get() {
      var compilerObj = transformEnvToObject(this._compiler);
      if ((_ramda || _load_ramda()).default.isEmpty(compilerObj)) return undefined;
      return compilerObj;
    },
    set: function set(compiler) {
      this._compiler = transformEnvToObject(compiler);
    }
  }, {
    key: 'tester',
    get: function get() {
      var testerObj = transformEnvToObject(this._tester);
      if ((_ramda || _load_ramda()).default.isEmpty(testerObj)) return undefined;
      return testerObj;
    },
    set: function set(tester) {
      this._tester = transformEnvToObject(tester);
    }
  }], [{
    key: 'composePath',
    value: function composePath(bitPath) {
      return (_path || _load_path()).default.join(bitPath, (_constants || _load_constants()).BIT_JSON);
    }
  }, {
    key: 'hasExisting',
    value: function () {
      var _ref6 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee5(bitPath) {
        return (_regenerator || _load_regenerator()).default.wrap(function _callee5$(_context5) {
          while (1) {
            switch (_context5.prev = _context5.next) {
              case 0:
                return _context5.abrupt('return', (_fsExtra || _load_fsExtra()).default.exists(this.composePath(bitPath)));

              case 1:
              case 'end':
                return _context5.stop();
            }
          }
        }, _callee5, this);
      }));

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

      return hasExisting;
    }()
  }, {
    key: 'removeIfExist',
    value: function () {
      var _ref7 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee6(bitPath) {
        return (_regenerator || _load_regenerator()).default.wrap(function _callee6$(_context6) {
          while (1) {
            switch (_context6.prev = _context6.next) {
              case 0:
                if (!(_fsExtra || _load_fsExtra()).default.exists(this.composePath(bitPath))) {
                  _context6.next = 2;
                  break;
                }

                return _context6.abrupt('return', (_fsExtra || _load_fsExtra()).default.remove(this.composePath(bitPath)));

              case 2:
                return _context6.abrupt('return', false);

              case 3:
              case 'end':
                return _context6.stop();
            }
          }
        }, _callee6, this);
      }));

      function removeIfExist(_x15) {
        return _ref7.apply(this, arguments);
      }

      return removeIfExist;
    }()
  }]);

  return AbstractBitJson;
}();

exports.default = AbstractBitJson;


var transformEnvToObject = function transformEnvToObject(env) {
  if (typeof env === 'string') {
    if (env === (_constants || _load_constants()).NO_PLUGIN_TYPE) return {};
    return {
      [env]: {}
    };
  }
  return env;
};

var getEnvsProps = function getEnvsProps(consumerPath, scopePath, envName, envObject, bitJsonPath, envType, context) {
  var envProps = {
    name: envName,
    consumerPath,
    scopePath,
    rawConfig: envObject.rawConfig,
    files: envObject.files,
    bitJsonPath,
    options: envObject.options,
    envType,
    context
  };
  return envProps;
};