'use strict';

/**
 * Holds instances of configured DataSources
 * @type {Map<string, DataSource>}
 */
class DataSourceRegistry extends Map {
  /**
   * @param {Function} requireFn used to require() the loader
   * @param {string} rootPath project root
   * @param {object} config configuration to load
   */
  load(requireFn, rootPath, config = {}) {
    for (const [name, settings] of Object.entries(config)) {
      if (!settings.hasOwnProperty('require')) {
        throw new Error(`DataSource [${name}] does not specify a 'require'`);
      }

      if (typeof settings.require !== 'string') {
        throw new TypeError(`DataSource [${name}] has an invalid 'require'`);
      }

      const sourceConfig = settings.config || {};

      let loader = null;

      // relative path to require
      if (settings.require[0] === '.') {
        loader = require(rootPath + '/' + settings.require);
      } else if (!settings.require.includes('.')) {
        loader = require(settings.require);
      } else {
        const [moduleName, exportName] = settings.require.split('.');
        loader = requireFn(moduleName)[exportName];
      }

      const instance = new loader(sourceConfig, rootPath);
      if (!('hasData' in instance)) {
        throw new Error(`Data Source ${name} requires at minimum a 'hasData(config): boolean' method`);
      }
      instance.name = name;

      this.set(name, instance);
    }
  }
}

module.exports = DataSourceRegistry;