{"size": 2810, "ext": "js", "max_stars_repo_path": "lib/Container.js", "max_stars_repo_name": "Spomni/toweran", "max_stars_repo_stars_event_min_datetime": null, "max_stars_repo_stars_event_max_datetime": null, "max_issues_repo_path": "lib/Container.js", "max_issues_repo_name": "Spomni/toweran", "max_issues_repo_issues_event_min_datetime": null, "max_issues_repo_issues_event_max_datetime": null, "max_forks_repo_path": "lib/Container.js", "max_forks_repo_name": "Spomni/toweran", "max_forks_repo_forks_event_min_datetime": null, "max_forks_repo_forks_event_max_datetime": null}
{"max_stars_count": null, "max_issues_count": null, "max_forks_count": null, "avg_line_length": 22.8455284553, "max_line_length": 242, "alphanum_fraction": 0.6701067616}
'use strict'

const {
  must,
  C,
  ContainerInterface,
  ContainerRegistration,
} = toweran

/**
 * IoC Container
 * TODO: add bind, allow to reconnect resolvers on register stage, but restrict on boot and further @url https://trello.com/c/HLxNtFVY/74-di-add-bind-re-bind-that-allow-to-reconnect-resolvers-on-register-stage-but-restrict-on-boot-and-further
 */
class Container extends ContainerInterface {
  /**
   * Constructor
   */
  constructor() {
    super()

    /**
     * IoC Container
     * @type {Container<IInstanceWrapper<any>>}
     */
    this._addictContainer = new (require('addict-ioc').Container)()

    //Register itself
    this.instance('container', this)
  }

  /**
   * Register something to the container
   * @param {string|symbol} key
   * @param {*} concrete
   * @return {ContainerRegistrationInterface}
   */
  register(key, concrete) {
    must.be.notEmptyStringOrSymbol(key)

    return new ContainerRegistration(this._addictContainer, key, concrete)
  }

  /**
   * Register something to the container as instance
   * @param {string|symbol} key
   * @param {*} concrete
   * @return {ContainerInterface}
   */
  instance(key, concrete) {
    must.be.notEmptyStringOrSymbol(key)

    this._addictContainer.registerObject(key, concrete)

    return this
  }

  /**
   * Get resolved from the container
   * @param {string|symbol} key
   * @return {*}
   */
  get(key) {
    must.be.notEmptyStringOrSymbol(key)

    return this._addictContainer.resolve(key)
  }

  /**
   * Check if already registered
   * @param {string|symbol} key
   * @return {boolean}
   */
  has(key) {
    must.be.notEmptyStringOrSymbol(key)

    return this._addictContainer.isRegistered(key)
  }

  /**
   * Register and override if already registered
   * @param {string|symbol} key
   * @param {*} concrete
   * @return {ContainerRegistrationInterface}
   */
  registerForce(key, concrete) {
    must.be.notEmptyStringOrSymbol(key)

    if (C.APP_MODE.TESTING !== process.env.NODE_ENV) {
      throw new Error(`Force registration in the container allowed only in testing environment!`)
    }

    if (this.has(key)) {
      this._addictContainer.unregister(key)
    }

    return this.register(key, concrete)
  }

  /**
   * Register and override if already registered as an instance
   * @param {string|symbol} key
   * @param {*} concrete
   * @return {ContainerInterface}
   */
  instanceForce(key, concrete) {
    must.be.notEmptyStringOrSymbol(key)

    if (C.APP_MODE.TESTING !== process.env.NODE_ENV) {
      throw new Error(`Force registration in the container allowed only in testing environment!`)
    }

    if (this.has(key)) {
      this._addictContainer.unregister(key)
    }

    this._addictContainer.registerObject(key, concrete)

    return this
  }
}

module.exports = Container
