/*
 * AXFCommSend.cpp
 */

#include "AXConfig.hpp"
#include "AXFCommSendInternal.hpp"
#include "AXFTask.hpp"
#include "AXFTimerInternal.hpp"
#include "AXFMailboxInternal.hpp"
#include "AXFObjectName.hpp"
#include "AXFMutex.hpp"

#define TASK_STACK_SIZE		2048

static const std::string commSendTaskName("commS");

AXFCommSendInternal::AXFCommSendInternal(char* sendBuf, char* rcvBuf,
                                         AXFMutex* mutex,
                                         AXFMailboxInternal* mailbox,
                                         AXFCommInternal* comm, AXFTask* thread)
    : m_sendBuf(sendBuf),
      m_rcvBuf(rcvBuf),
      m_mutex(mutex),
      m_mailbox(mailbox),
      m_comm(comm),
      m_thread(thread),
      m_isActive(false) {
}

AXFCommSendInternal::~AXFCommSendInternal() {
  delete m_thread;
  m_thread = NULL;

  delete m_comm;
  m_comm = NULL;

  delete m_mailbox;
  m_mailbox = NULL;

  delete m_mutex;
  m_mutex = NULL;

  delete[] m_rcvBuf;
  m_rcvBuf = NULL;

  delete[] m_sendBuf;
  m_sendBuf = NULL;
}

AXFCommSendInternal::axcommSendStatus AXFCommSendInternal::init(AXComm_t type) {
  axcommSendStatus stat = AXCOMMSEND_ERROR;
  int devno = (type & ~AXCOMM_TYPE_MASK);
  std::ostringstream devNoStr;

  if (devno >= 100) {
    stat = AXCOMMSEND_ERROR_PARAM;
    goto err;
  }
  devNoStr << devno;

  if (NULL == m_sendBuf) {
    stat = AXCOMMSEND_ERROR_NEW;
    goto err;
  }

  if (NULL == m_rcvBuf) {
    stat = AXCOMMSEND_ERROR_NEW;
    goto err;
  }

  if (NULL == m_mutex) {
    stat = AXCOMMSEND_ERROR_NEW;
    goto err_1;
  }
  if (AXFMutex::MUTEX_SUCCESS != m_mutex->init()) {
    stat = AXCOMMSEND_ERROR_INIT_MUTEX;
    goto err_2;
  }

  if (NULL == m_mailbox) {
    stat = AXCOMMSEND_ERROR_NEW;
    goto err_2;
  }

  if (AXFMailboxInternal::QUEUE_SUCCESS
      != m_mailbox->create(AXConfig.stageComm[AXCONFIG_STAGE_DEFAULT].send.maxBufCount,
                           AXConfig.stageComm[AXCONFIG_STAGE_DEFAULT].send.maxBufSize)) {
    stat = AXCOMMSEND_ERROR_INIT_MAILBOX;
    goto err_3;
  }

  if (NULL == m_comm) {
    stat = AXCOMMSEND_ERROR_NEW;
    goto err_3;
  }
  if (AXFCommInternal::COMM_SUCCESS != m_comm->init(type)) {
    stat = AXCOMMSEND_ERROR_INIT_AXCOMM;
    goto err_4;
  }

  if (NULL == m_thread) {
    stat = AXCOMMSEND_ERROR_NEW;
    goto err_4;
  }
  m_isActive = true;
  if (AXFTask::TASK_SUCCESS
      != m_thread->create(commSendTaskName.c_str() + devNoStr.str(),
                          AXFTask::AXF_PRIORITY_HIGH_2, TASK_STACK_SIZE,
                          &AXFCommSendInternal::do_worker, this)) {
    stat = AXCOMMSEND_ERROR_INIT_TASK;
    goto err_5;
  }

  return AXCOMMSEND_SUCCESS;

  err_5:

  delete m_thread;
  m_thread = NULL;

  err_4:

  delete m_comm;
  m_comm = NULL;

  err_3:

  delete m_mailbox;
  m_mailbox = NULL;

  err_2:

  delete m_mutex;
  m_mutex = NULL;

  err_1:

  delete[] m_sendBuf;
  m_sendBuf = NULL;

  err:

  m_isActive = false;
  return stat;
}

AXFCommSendInternal::axcommSendStatus AXFCommSendInternal::join() {
  axcommSendStatus stat = AXCOMMSEND_SUCCESS;

  if (false == m_isActive) {
    return stat;
  }

  m_isActive = false;
  /* 送信データ待ち状態から抜けるために、空データを送信する */
  m_mailbox->send(0, NULL, 0);
  m_thread->join();
  return stat;
}

int AXFCommSendInternal::send(AXFObjectName& name, AXFEvent_t eventId,
                              void* data, int size) {
  int stat;
  INT32_t sendSize;

  if (false == m_isActive) {
    return -100;
  }

  if (AXFMutex::MUTEX_SUCCESS != m_mutex->lock()) {
    return -101;
  }

  sendSize = m_comm->setPacket(m_sendBuf, AXConfig.stageComm[AXCONFIG_STAGE_DEFAULT].send.maxBufSize,
                               name.getFullActorName().c_str(), eventId, data, size);
  if (0 > sendSize) {
    stat = -102;
    goto err;
  }

  stat = m_mailbox->send(eventId, m_sendBuf, sendSize);

  err:

  m_mutex->unlock();
  return stat;
}

AXFCommSendInternal::axcommSendStatus AXFCommSendInternal::cancel() {
  m_isActive = false;
  return AXCOMMSEND_SUCCESS;
}

void* AXFCommSendInternal::do_worker_sub() {
  int stat;
  AXFEvent_t eventId;
  int receivedSize;

  AXFTimerInternal::maskTimerSignal();

  while (m_isActive) {
    receivedSize = m_mailbox->receive(&eventId, m_rcvBuf,
                                      AXConfig.stageComm[AXCONFIG_STAGE_DEFAULT].send.maxBufSize);

    if ((false == m_isActive)) {
      break;
    }

#ifdef NEVER
    printf("@comSend 0x%x:%d\n", eventId, receivedSize);
#endif

    stat = m_comm->writeSync((char *) m_rcvBuf, receivedSize);
    if (0 > stat) {
      continue;
    }
  }

  if (m_thread != NULL) {
    m_thread->exitSelf();
  }
  //@UTIGN exitSelf
  return NULL;
}
