/*------------------------------------------------------------------------------
| Function    : receive_message_ack
+------------------------------------------------------------------------------
| Description : 
|
| Parameters  : 
|
| Returns     : void
+----------------------------------------------------------------------------*/
t_tx_event receive_message_ack(void)
{
  receive_message_header(FALSE);
  if(rx_header.fields.ctrl && rx_header.fields.ack && !rx_header.fields.length) 
  {
    return tx_header.fields.more ? tx_event_more : tx_event_no_more;
  }
  else
  {
    DEBUG_LOGF_ERROR("USB: Expected ACK but received MSG");
    return tx_event_done;
  }
}
// Handle each peer connection in their own handlers
void *client_connection_handler(void *metadata) {
  struct connection_details * cd = (struct connection_details*) metadata;
  struct message_header mh;
  while (1) {
    receive_message_header(cd->serving_fd, &mh);
    // FIXME: The condition where socket server gets a connection
    // from the peer but the user didn't allocate a SocketChannel
    // for the peer.This can even happen if adapter is instantiated
    // first and SocketChannel is allocated for the peer subsequently
    // For now assume the user will maintain the right order i.e
    // allocate a SocketChannel for all peers and then instantiate
    // the adapter.
    /*      if(cd->sa->channels.size() < mh.rank || cd->sq->channels.at(mh.rank) == NULL){
            printf("ERROR:No SocketChannel assigned for the peer with rank [%d]...terminating the thread handler\n", mh.rank);
            // FIXME: Notify the client and exit
            pthread_exit();
            }
    */
    // From the peer rank locate the local SocketChannel for that
    // peer and sets it's serving_fd
    SocketChannel* sc = cd->sa->channels->at(mh.rank).get();
    sc->serving_fd = cd->serving_fd;
    uint8_t* read_buffer = new uint8_t[mh.size];
    uint8_t* marker = read_buffer;
    int cur_cnt = 0;
    int max_buff = 0;
    while (cur_cnt < mh.size) {
      if ((mh.size - cur_cnt) > 256)
        max_buff = 256;
      else
        max_buff = mh.size - cur_cnt;

      int n = read(sc->serving_fd, marker, max_buff);
      CHECK(n >= 0) << "ERROR: Reading data from client";
      marker = marker + n;
      cur_cnt = cur_cnt + n;
    }
    // Wrap the received message in an object QueuedMessage and
    // push it to the local receive queue of the peer's
    // SocketChannel
    QueuedMessage* mq = new QueuedMessage(mh.type,
                                          mh.size, read_buffer);
    if(mh.type == DIFF)
      sc->receive_queue.push(mq);
    else
      sc->receive_queue_ctrl.push(mq);
  }
  return NULL;
}
/*------------------------------------------------------------------------------
| Function    : rx_usb
+------------------------------------------------------------------------------
| Description : 
|
| Parameters  : 
|
| Returns     : void
+----------------------------------------------------------------------------*/
void rx_usb(t_rx_event event)
{
  do
  {
    LOGF("USB RX: %s - %s", rx_state_names[rx_state], rx_events[event]);

    switch(rx_state)
    {
      case rx_state_null:
        switch(event)
        {
          case rx_event_init:
            rx_state = rx_state_idle;
            event = rx_event_done;
            break;
        }
        break;

      case rx_state_idle:
        switch(event)
        {
          case rx_event_receive:
            if(tx_state == tx_state_idle)
            {
              rx_state = rx_state_awaiting_header;
              event = receive_message_header(TRUE);
            }
            else
            {
              rx_state = rx_state_pending;
              event = rx_event_done;
            }
            break;

          case rx_event_tx_idle:
            event = rx_event_done;
            break;
        }
        break;

      case rx_state_pending:
        switch(event)
        {
          case rx_event_more:
          case rx_event_tx_idle:
            rx_state = rx_state_awaiting_header;
            event = receive_message_header(TRUE);
            break;

          case rx_event_receive:
            event = rx_event_done;
            break;
        }
        break;

      case rx_state_awaiting_header:
        switch(event)
        {
          case rx_event_header_received:
            rx_state = rx_state_awaiting_data;
            event = receive_message_data();
            break;

          case rx_event_header_failed:
            rx_state = rx_state_idle;
            event = rx_event_done;
            break;
        }
        break;

      case rx_state_awaiting_data:
        switch(event)
        {
          case rx_event_data_received:
            event = check_more_data();
            if(event == rx_event_more) 
            {
              rx_state = rx_state_pending;
            }
            else
            {
              rx_state = rx_state_idle;
              tx_usb(tx_event_rx_idle);
            }
            deliver_message_data();
            break;

          case rx_event_data_failed:
            rx_state = rx_state_idle;
            event = rx_event_done;
            break;
        }
        break;
    }
  } while(event != rx_event_done);
}