text: const KarmaEventEmitter = require('../events').EventEmitter
  const EventEmitter = require('events').EventEmitter
  
  const log = require('../logger').create('launcher')
  const helper = require('../helper')
  
  const BEING_CAPTURED = 'BEING_CAPTURED'
  const CAPTURED = 'CAPTURED'
  const BEING_KILLED = 'BEING_KILLED'
  const FINISHED = 'FINISHED'
  const RESTARTING = 'RESTARTING'
  const BEING_FORCE_KILLED = 'BEING_FORCE_KILLED'
  
  /**
   * Base launcher that any custom launcher extends.
   */
  function BaseLauncher (id, emitter) {
    if (this.start) {
      return
    }
  
    // TODO(vojta): figure out how to do inheritance with DI
    Object.keys(EventEmitter.prototype).forEach(function (method) {
      this[method] = EventEmitter.prototype[method]
    }, this)
  
    this.bind = KarmaEventEmitter.prototype.bind.bind(this)
    this.emitAsync = KarmaEventEmitter.prototype.emitAsync.bind(this)
  
    this.id = id
    this._state = null
    Object.defineProperty(this, 'state', {
      get: () => {
        return this._state
      },
      set: (toState) => {
        log.debug(`${this._state} -> ${toState}`)
        this._state = toState
      }
    })
  
    this.error = null
  
    let killingPromise
    let previousUrl
  
    this.start = function (url) {
      previousUrl = url
  
      this.error = null
      this.state = BEING_CAPTURED
      this.emit('start', url + '?id=' + this.id + (helper.isDefined(this.displayName) ? '&displayName=' + encodeURIComponent(this.displayName) : ''))
    }
  
    this.kill = function () {
      // Already killed, or being killed.
      if (killingPromise) {
        return killingPromise
      }
  
      killingPromise = this.emitAsync('kill').then(() => {
        this.state = FINISHED
      })
  
      this.state = BEING_KILLED
  
      return killingPromise
    }
  
    this.forceKill = function () {
      this.kill()
      this.state = BEING_FORCE_KILLED
  
      return killingPromise
    }
  
    this.restart = function () {
      if (this.state === BEING_FORCE_KILLED) {
        return
      }
  
      if (!killingPromise) {
        killingPromise = this.emitAsync('kill')
      }
  
      killingPromise.then(() => {
        if (this.state === BEING_FORCE_KILLED) {
          this.state = FINISHED
        } else {
          killingPromise = null
          log.debug(`Restarting ${this.name}`)
          this.start(previousUrl)
        }
      })
  
      this.state = RESTARTING
    }
  
    this.markCaptured = function () {
      if (this.state === BEING_CAPTURED) {
        this.state = CAPTURED
      }
    }
  
    this.isCaptured = function () {
      return this.state === CAPTURED
    }
  
    this.toString = function () {
      return this.name
    }
  
    this._done = function (error) {
      killingPromise = killingPromise || Promise.resolve()
  
      this.error = this.error || error
      this.emit('done')
  
      if (this.error && this.state !== BEING_FORCE_KILLED && this.state !== RESTARTING) {
        emitter.emit('browser_process_failure', this)
      }
  
      this.state = FINISHED
    }
  
    this.STATE_BEING_CAPTURED = BEING_CAPTURED
    this.STATE_CAPTURED = CAPTURED
    this.STATE_BEING_KILLED = BEING_KILLED
    this.STATE_FINISHED = FINISHED
    this.STATE_RESTARTING = RESTARTING
    this.STATE_BEING_FORCE_KILLED = BEING_FORCE_KILLED
  }
  
  BaseLauncher.decoratorFactory = function (id, emitter) {
    return function (launcher) {
      BaseLauncher.call(launcher, id, emitter)
    }
  }
  
  module.exports = BaseLauncher
  