# ping_pong/events/orders_order_fill.js

    'use strict'

    const { Order } = require('bfx-api-node-models')
    const genCID = require('../../util/gen_client_id')
    const { Config } = require('bfx-api-node-core')
    const { DUST } = Config

    /**
     * Triggered on atomic order fill. If it was a `ping`, the associated `pong`
     * is submitted. Otherwise it if was a `pong` and the instance was configured
     * as `endless`, the associated `ping` is submitted. If not `endless`, nothing
     * is done.
     *
     * @memberOf module:PingPong
     * @listens AOHost~ordersOrderFill
     *
     * @param {AOInstance} instance - AO instance
     * @param {object} order - the order that filled
     * @returns {Promise} p - resolves on completion
     */
    const onOrdersOrderFill = async (instance = {}, order) => {
      const { state = {}, h = {} } = instance
      const { args = {}, gid, pingPongTable, activePongs } = state
      const { emit, debug, updateState } = h
      const { price } = order
      const {
        endless, submitDelay, symbol, pingAmount, pongAmount, hidden, lev,
        _margin, _futures
      } = args

      if (order.amount > DUST) { // not fully filled
        return
      }

      const sharedOrderParams = {
        meta: { _HF: 1 },
        symbol,
        hidden,
        gid
      }

      if (_futures) {
        sharedOrderParams.lev = lev
      }

      const {
        [price]: pongPrice,
        ...nextPingPongTable
      } = pingPongTable

      if (!pongPrice) {
        const {
          [price]: pingPrice,
          ...nextActivePongs
        } = activePongs

        if (pingPrice) {
          debug('pong filled: %f', price)

          // NOTE: Shadows from above
          const nextPingPongTable = !endless
            ? pingPongTable
            : {
              ...pingPongTable,
              [pingPrice]: price
            }

          await updateState(instance, {
            activePongs: nextActivePongs,
            pingPongTable: nextPingPongTable
          })

          if (endless) {
            const pingOrder = new Order({
              ...sharedOrderParams,

              price: pingPrice,
              cid: genCID(),
              type: _margin || _futures ? Order.type.LIMIT : Order.type.EXCHANGE_LIMIT,
              amount: pingAmount
            })

            await emit('exec:order:submit:all', gid, [pingOrder], submitDelay)
          } else if (
            Object.keys(pingPongTable).length === 0 &&
            Object.keys(nextActivePongs).length === 0
          ) {
            debug('all orders filled')
            await emit('exec:stop')
          }
        }

        return
      }

      const pongOrder = new Order({
        ...sharedOrderParams,

        price: pongPrice,
        cid: genCID(),
        type: _margin || _futures ? Order.type.LIMIT : Order.type.EXCHANGE_LIMIT,
        amount: -pongAmount
      })

      debug('submitting pong order %f for ping %f', pongPrice, price)

      await emit('exec:order:submit:all', gid, [pongOrder], submitDelay)
      await updateState(instance, {
        pingPongTable: nextPingPongTable,
        activePongs: {
          ...activePongs,
          [pongPrice]: price
        }
      })
    }

    module.exports = onOrdersOrderFill