/*
 * AXFCommReceive.cpp
 */

#include "AXConfig.hpp"
#include "AXFCommReceiveInternal.hpp"
#include "AXFTask.hpp"
#include "AXFTimerInternal.hpp"
#include "AXFStage.hpp"
#include "AXFMailboxInternal.hpp"
#include "AXFStdioInternal.hpp"

#include <string>

#define TASK_STACK_SIZE		2048

static const std::string commReceiveTaskName("commR");

AXFCommReceiveInternal::AXFCommReceiveInternal(AXFCommInternal* comm,
                                               AXFTask* thread, char* rcvBuf)
    : m_comm(comm),
      m_thread(thread),
      m_isActive(false),
      m_rcvBuf(rcvBuf) {
}

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

  delete m_comm;
  m_comm = NULL;

  delete[] m_rcvBuf;
  m_rcvBuf = NULL;
}

AXFCommReceiveInternal::axcommReceiveStatus AXFCommReceiveInternal::init(
    AXComm_t type) {
  axcommReceiveStatus stat = AXCOMMRECEIVE_ERROR;
  int devno = (type & ~AXCOMM_TYPE_MASK);
  std::ostringstream devNoStr;

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

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

  if (NULL == m_comm) {
    stat = AXCOMMRECEIVE_ERROR_NEW;
    goto err_1;
  }

  if (AXFCommInternal::COMM_SUCCESS != m_comm->init(type)) {
    stat = AXCOMMRECEIVE_ERROR_INIT_AXCOMM;
    goto err_2;
  }

  if (NULL == m_thread) {
    stat = AXCOMMRECEIVE_ERROR_NEW;
    goto err_2;
  }

  m_isActive = true;
  if (AXFTask::TASK_SUCCESS
      != m_thread->create(commReceiveTaskName.c_str() + devNoStr.str(),
                          AXFTask::AXF_PRIORITY_HIGH_2, TASK_STACK_SIZE,
                          &AXFCommReceiveInternal::do_worker, this)) {
    stat = AXCOMMRECEIVE_ERROR_INIT_TASK;
    goto err_3;
  }

  return AXCOMMRECEIVE_SUCCESS;

  err_3:

  delete m_thread;
  m_thread = NULL;

  err_2:

  delete m_comm;
  m_comm = NULL;

  err_1:

  delete[] m_rcvBuf;
  m_rcvBuf = NULL;

  err:

  return stat;
}

AXFCommReceiveInternal::axcommReceiveStatus AXFCommReceiveInternal::join() {
  axcommReceiveStatus stat = AXCOMMRECEIVE_SUCCESS;

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

  m_isActive = false;
  /* 受信データ待ち状態から抜けるために、ダミー・データを書き込む */
  INT32_t dummy = 0;
  m_comm->writeSync((char *) &dummy, sizeof(dummy));
  m_thread->join();
  return stat;
}

AXFCommReceiveInternal::axcommReceiveStatus AXFCommReceiveInternal::cancel() {
  m_isActive = false;
  return AXCOMMRECEIVE_SUCCESS;
}

void* AXFCommReceiveInternal::do_worker_sub() {
  int stat;
  AXFEvent_t eventId;
  AXFMailboxInternal* mailbox;

  AXFTimerInternal::maskTimerSignal();

  while (m_isActive) {
    stat = m_comm->readSync(m_rcvBuf, AXConfig.stageComm[AXCONFIG_STAGE_DEFAULT].receive.maxBufSize);
    if (0 > stat) {
      continue;
    }

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

    eventId = m_comm->getEventId(m_rcvBuf);
#ifdef NEVER
    if (AXFEVENT_SYS_LOG== eventId) {
      AXFStdio stdio;
      std::string message = (char*)m_comm->getDataPtr(m_rcvBuf);
      std::cout << message.c_str() << axstdio::endl;
      stdio.flush();
      continue;
    }
#endif /* NEVER */

    AXFStageActorInfo* actorInfo = NULL;
    {
      AXFObjectName name(m_comm->getObjectNameStringPtr(m_rcvBuf));
      if (0 > AXFStage::getInstance()->getActorInfo(name, &actorInfo)) {
        // 自Stage内に送信先アクタが存在しない場合は、破棄する
        continue;
      }
    }
    mailbox = actorInfo->mailRef;

#ifdef NEVER
    printf("@comReceive 0x%x:%d:name=%s:dataSize%d\n", eventId, stat,
        m_comm->getObjectNameStringPtr(m_rcvBuf),
        m_comm->getDataSize(m_rcvBuf));
#endif

    if (0
        > mailbox->send(eventId, m_comm->getDataPtr(m_rcvBuf),
                        m_comm->getDataSize(m_rcvBuf))) {
      continue;
    }
  }

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