'use strict'

const EventEmitter = require('events').EventEmitter
const helper = require('./helper')

function bufferEvents (emitter, eventsToBuffer) {
  const listeners = []
  const eventsToReply = []

  function genericListener () {
    eventsToReply.push(Array.from(arguments))
  }

  eventsToBuffer.forEach((eventName) => {
    const listener = genericListener.bind(null, eventName)
    listeners.push(listener)
    emitter.on(eventName, listener)
  })

  return function () {
    listeners.forEach((listener, i) => {
      emitter.removeListener(eventsToBuffer[i], listener)
    })

    eventsToReply.forEach((args) => {
      EventEmitter.prototype.emit.apply(emitter, args)
    })

    listeners.length = 0
    eventsToReply.length = 0
  }
}

class KarmaEventEmitter extends EventEmitter {
  bind (object) {
    for (const method in object) {
      if (method.startsWith('on') && helper.isFunction(object[method])) {
        this.on(helper.camelToSnake(method.substr(2)), function () {
          // We do not use an arrow function here, to supply the caller as this.
          object[method].apply(object, Array.from(arguments).concat(this))
        })
      }
    }
  }

  emitAsync (name) {
    // TODO(vojta): allow passing args
    // TODO(vojta): ignore/throw if listener call done() multiple times
    let pending = this.listeners(name).length
    const deferred = helper.defer()

    this.emit(name, () => {
      if (!--pending) {
        deferred.resolve()
      }
    })

    if (!pending) {
      deferred.resolve()
    }

    return deferred.promise
  }
}

exports.EventEmitter = KarmaEventEmitter
exports.bufferEvents = bufferEvents
