# Source: utils/eventUtils.js

    /**
     * @file Manages helper functions to work with events
     * @author Ivan Violentov <ivan.violentov@jibrel.network>
     */

    import Promise from 'bluebird'
    import EventEmitter from 'events'

    import config from '../config'

    /**
     * @callback eventCallback
     *
     * @param {Object} error
     * @param {Object} event
     */

    /**
     * @function subscribe
     *
     * @description Subscribes to provided event
     *
     * @param {function} Event - Function for event subscribing
     * @param {object} [options={}] - Event options
     * @param {object} [options.filter] - Filter options by indexed event parameters
     * @param {(number|string)} [options.fromBlock] - The number of the earliest block
     * @param {(number|string)} [options.toBlock] - The number of the latest block
     * @param {(string|string[])} [options.address] - An address(es) to get logs from
     * @param {string[]} [options.topics] - Allows to manually set the topics for the event filter
     * @param {eventCallback} [callback] - Callback which fired for each event or error
     *
     * @returns {object} The event emitter has the following events:<br />
     * - data: Fires on each incoming event with the event object as argument<br />
     * - error: Fires when an error in the subscription occours
     */
    export function subscribe(Event, options = {}, callback) {
      const eventEmitter = new EventEmitter()

      /**
       * web3@0.x.x event takes filter and additional options in different params
       * web3@1.x.x event takes all options in one param
       */
      const { filter, ...additionalOptions } = options

      Event(filter, additionalOptions, (err, result) => {
        if (err) {
          /**
           * Error event
           *
           * @event subscribeErrorEvent
           * @type {object}
           */
          eventEmitter.emit('error', err)

          if (callback) {
            callback(err)
          }

          return
        }

        /**
         * Data event
         *
         * @event subscribeDataEvent
         * @type {object}
         */
        eventEmitter.emit('data', result)

        if (callback) {
          callback(null, result)
        }
      })

      return eventEmitter
    }

    /**
     * @async
     * @function getEvents
     *
     * @description Gets past events
     *
     * @param {function} Event - Function to get past events
     * @param {object} [options={}] - Event options
     * @param {object} [options.filter] - Filter options by indexed event parameters
     * @param {(number|string)} [options.fromBlock] - The number of the earliest block
     * @param {(number|string)} [options.toBlock] - The number of the latest block
     * @param {(string|string[])} [options.address] - An address(es) to get logs from
     * @param {string[]} [options.topics] - Allows to manually set the topics for the event filter
     *
     * @returns Promise that will be resolved with past events
     */
    export function getEvents(Event, options = {}) {
      /**
       * web3@0.x.x event takes filter and additional options in different params
       * web3@1.x.x event takes all options in one param
       */
      const { filter, ...additionalOptions } = options
      const event = Event(filter, additionalOptions)

      /**
       * event.get uses instance methods inside,
       * but bluebird promisify don't save context,
       * so need to bind to event object directly
       */
      return Promise
        .promisify(event.get.bind(event))()
        .timeout(
          config.promiseTimeout,
          new Error(`Can not get past events within ${config.promiseTimeout}ms`)
        )
    }