/*
 * AXFStage.cpp
 */

#include <vector>
#include "AXFStage.hpp"
#include "AXConfig.hpp"
#include "AXFEvent.hpp"
#include "AXFConditionVariableInternal.hpp"
#include "AXFMailboxInternal.hpp"
#include "AXFTimeDomainInternal.hpp"
#include "AXFShellInternal.hpp"
#include "AXFCommSendInternal.hpp"
#include "AXFCommReceiveInternal.hpp"
#include "AXFRingBufInternal.hpp"
#include "AXFCommRingBufInternal.hpp"
#include "AXFLogTaskInternal.hpp"
#include "AXFTimerTaskInternal.hpp"

#include <new>

// CPU間ログ転送用 共有メモリバッファサイズ
#define COM_MEM_LOG_SIZE		512

// CPU間ログ転送用 送信バッファサイズ
#define COM_MEM_LOG_SEND_BUF_SIZE	(COM_MEM_LOG_SIZE * 2)

// TimerTask用のスタックサイズ
#define TIMER_TASK_STACK_SIZE	2048

const int AXFSTAGE_NOTSTARTING = -1;

AXFStage* AXFStage::m_stage = NULL;
#ifndef	UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
AXFTimeDomainInternal* AXFStage::m_timeDomain = NULL;
#endif	/* UNUSE_CHRONO */
AXFCommSendInternal* AXFStage::m_commSend = NULL;
AXFCommReceiveInternal* AXFStage::m_commReceive = NULL;
AXFDaemonInternal* AXFStage::m_axdaemon = NULL;
AXFLogTaskInternal* AXFStage::m_logTask = NULL;
AXFTimerTaskInternal* AXFStage::m_timerTask = NULL;

AXFStage::AXFStage(AXFObjectName& stageName)
    : m_stageName(stageName),
      mActorInfoListCount(0) {
}

AXFStage::~AXFStage() {
}

bool AXFStage::createResource(AXFStageResource::resourceType type,
                              std::vector<AXFStageResourceInfo>* resourceInfo) {
  AXFStageActorInfo tmp;
  std::vector<AXFStageResourceInfo>::iterator pmActorInfo;

  if (NULL == resourceInfo) {
    return false;
  }
  if (0 >= resourceInfo->size()) {
    return false;
  }

  // Actor情報リストへ登録
  for (pmActorInfo = resourceInfo->begin(); pmActorInfo != resourceInfo->end();
      ++pmActorInfo) {
    tmp.type = type;
    tmp.name = pmActorInfo->name;
    tmp.mailMaxCount = pmActorInfo->mailMaxCount;
    tmp.mailMaxSize = pmActorInfo->mailMaxSize;
    tmp.mailRef = new (std::nothrow) AXFMailboxInternal;
    if ((NULL == tmp.mailRef)
        || (AXFMailboxInternal::QUEUE_SUCCESS
            != tmp.mailRef->create(pmActorInfo->mailMaxCount,
                                   pmActorInfo->mailMaxSize))) {
      delete tmp.mailRef;
      deleteResource(type);    // 取得登録済みの全リソース解放
      return false;
    }
    tmp.objRef = NULL;
    tmp.startOrder = AXFSTAGE_NOTSTARTING;
    tmp.actorPriority = pmActorInfo->actorPriority;
    tmp.actorStackSize = pmActorInfo->actorStackSize;
    tmp.actorWatchDogTime = pmActorInfo->actorWatchDogTime;

    mActorInfoList.push_back(tmp);
    mAllMailboxRef.push_back(tmp.mailRef);
    mActorInfoListCount++;
  }

  return true;
}

bool AXFStage::addActors(AXFStageResource::resourceType type,
                         std::vector<AXFStageStartInfo>* startInfo) {
  int index = 0;
  std::vector<AXFStageStartInfo>::iterator pmActorInfo;

  if (NULL == startInfo) {
    return false;
  }
  if (0 >= startInfo->size()) {
    return false;
  }

  // Actor情報リストへ登録
  for (pmActorInfo = startInfo->begin(); pmActorInfo != startInfo->end();
      ++pmActorInfo) {
    if (false == getActorInfoListIndex(pmActorInfo->name, &index)) {
      // 指定されたActorは未登録
      return false;
    }

    mActorInfoList[index].objRef = pmActorInfo->objRef;

    if ((AXFStageResource::TYPE_AXM == type)
        && (AXFSTAGE_NOTSTARTING != pmActorInfo->startOrder)) {
      mActorInfoList[index].startOrder = pmActorInfo->startOrder + 2;  // axdaemon, axshell
    } else {
      mActorInfoList[index].startOrder = pmActorInfo->startOrder;
    }
  }

  if (type != AXFStageResource::TYPE_AXM) {
    return true;
  }

  // 開始順位に従い昇順ソート
  sortActorInfoList();

  return true;
}

bool AXFStage::startActors(AXFStageResource::resourceType type) {
  int i = 0;

  for (i = 0; i < mActorInfoListCount; i++) {
    if (mActorInfoList[i].type != type) {
      continue;
    }

    // アクタを生成する
    mActorInfoList[i].objRef->create(mActorInfoList[i].actorPriority,
                                     mActorInfoList[i].actorStackSize);
  }

  // 開始指示指定されたActorのみ起動
  for (i = 0; i < mActorInfoListCount; i++) {
    if (mActorInfoList[i].type != type) {
      continue;
    }
    if (AXFSTAGE_NOTSTARTING == mActorInfoList[i].startOrder) {
      continue;
    }

    // 開始メッセージ発行
    mActorInfoList[i].mailRef->send(AXFEVENT_LIFECYCLE_START, NULL, 0);
  }

  return true;
}

bool AXFStage::exitActors(AXFStageResource::resourceType type) {
  int i = 0;

  // 起動と逆順に停止要求、終了要求、終了完了待ちを行う。
  for (i = mActorInfoListCount - 1; i >= 0; i--) {
    if (mActorInfoList[i].type != type) {
      continue;
    }
    if (AXFSTAGE_NOTSTARTING == mActorInfoList[i].startOrder) {
      continue;
    }

    if (NULL == mActorInfoList[i].mailRef) {
      continue;
    }

    // 停止メッセージ発行
    mActorInfoList[i].mailRef->send(AXFEVENT_LIFECYCLE_STOP, NULL, 0);

    // 終了メッセージ発行
    mActorInfoList[i].mailRef->send(AXFEVENT_LIFECYCLE_EXIT, NULL, 0);

    // Actorの処理終了待ち
    mActorInfoList[i].objRef->join();
  }

  // 当Stageで取得したリソース（Mailbox）の解放
  deleteResource(type);

  return true;
}

bool AXFStage::deleteResource(AXFStageResource::resourceType type) {
  int i = 0;
  int listCount = mActorInfoListCount;

  if (0 >= mActorInfoListCount) {
    return true;
  }

  for (i = listCount - 1; i >= 0; i--) {
    if (mActorInfoList[i].type != type) {
      continue;
    }
    if (NULL == mActorInfoList[i].mailRef) {
      continue;
    }

    delete mActorInfoList[i].objRef;
    mActorInfoList[i].objRef = NULL;

    delete mActorInfoList[i].mailRef;
    mActorInfoList[i].mailRef = NULL;
  }

  if (AXFStageResource::TYPE_AXF == type) {
    mActorInfoList.clear();
    mAllMailboxRef.clear();
    mActorInfoListCount = 0;
  }

  return true;
}

bool AXFStage::getActorInfo(std::vector<AXFStageActorInfo>** actorInfoList) {
  *actorInfoList = &mActorInfoList;
  return true;
}

int AXFStage::getActorInfo(const AXFObjectName& actorName,
                           AXFStageActorInfo** actorInfo) {
  int index = -1;

  if (false == getActorInfoListIndex(actorName, &index)) {
    // 指定されたActorは未登録
    return -1;
  }

  *actorInfo = &mActorInfoList[index];
  return index;
}

int AXFStage::getActorInfo(const AXFObjectName& actorName,
                           AXFActor** actorObjRef) {
  int index = -1;

  if (false == getActorInfoListIndex(actorName, &index)) {
    // 指定されたActorは未登録
    return -1;
  }

  *actorObjRef = mActorInfoList[index].objRef;
  return index;
}

int AXFStage::getActorInfo(const AXFObjectName& actorName,
                           AXFMailboxInternal** actorMailRef) {
  int index = -1;

  if (false == getActorInfoListIndex(actorName, &index)) {
    // 指定されたActorは未登録
    return -1;
  }

  *actorMailRef = mActorInfoList[index].mailRef;
  return index;
}

std::vector<AXFMailboxInternal *>* AXFStage::getAllMailbox() {
  return &mAllMailboxRef;
}

bool AXFStage::getStageName(AXFObjectName* stageName) {
  *stageName = m_stageName;
  return true;
}

void AXFStage::sortActorInfoList() {
  int i = 0;
  int j = 0;
  AXFStageActorInfo tmp;

  for (i = 0; i < mActorInfoListCount - 1; i++) {

    for (j = mActorInfoListCount - 1; j > i; j--) {
      if (mActorInfoList[j].startOrder < mActorInfoList[i].startOrder) {
        tmp = mActorInfoList[j];
        mActorInfoList[j] = mActorInfoList[j - 1];
        mActorInfoList[j - 1] = tmp;
      }
    }
  }

  return;
}

bool AXFStage::getActorInfoListIndex(const AXFObjectName& actorName,
                                     int* index) {
  for (int i = 0; i < mActorInfoListCount; i++) {
    if (true == mActorInfoList[i].name.isMatch(actorName)) {
      *index = i;
      return true;
    }
  }
  return false;
}

void AXFStage::create(AXFObjectName& name) {
  if (NULL != m_stage) {
    return;
  }

  // Stage・インスタンスの生成
  m_stage = new (std::nothrow) AXFStage(name);

#ifndef	UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
  // TimeDomain・インスタンスの生成
  m_timeDomain = new (std::nothrow) AXFTimeDomainInternal();
#endif	/* UNUSE_CHRONO */

  // CPU間・プロセス間送信スレッド・インスタンスの生成
  AXFStage::m_commSend = new (std::nothrow) AXFCommSendInternal(
      new (std::nothrow) char[AXConfig.stageComm[AXCONFIG_STAGE_DEFAULT].send.maxBufSize],
      new (std::nothrow) char[AXConfig.stageComm[AXCONFIG_STAGE_DEFAULT].send.maxBufSize],
      new (std::nothrow) AXFMutex(), new (std::nothrow) AXFMailboxInternal,
      new (std::nothrow) AXFCommInternal(), new (std::nothrow) AXFTask());

  // CPU間・プロセス間受信スレッド・インスタンスの生成
  m_commReceive = new (std::nothrow) AXFCommReceiveInternal(
      new (std::nothrow) AXFCommInternal(), new (std::nothrow) AXFTask(),
      new (std::nothrow) char[AXConfig.stageComm[AXCONFIG_STAGE_DEFAULT].receive.maxBufSize]);

  // LogTask・インスタンスの生成
  AXFRingBufInternal *logSendBuf =
      (isRW == LOG_WRITE) ?
          new (std::nothrow) AXFRingBufInternal(
              new (std::nothrow) char[COM_MEM_LOG_SEND_BUF_SIZE], COM_MEM_LOG_SEND_BUF_SIZE,
              NULL, new (std::nothrow) AXFMutex(),
              new (std::nothrow) AXFConditionVariableInternal(), NULL) :
          NULL;

  AXFCommRingBufInternal *logCommBuf = new (std::nothrow) AXFCommRingBufInternal(
			// baba 現状のメモリ設定から下記を設定　※メモリ設定変更時は本設定も変更必要有
      (char *)(0x2005FE00 + 4*2),
      512 - 4*2,
      (volatile int *)(0x2005FE00 + 0),
      (volatile int *)(0x2005FE00 + 4)
      );

  m_logTask = new (std::nothrow) AXFLogTaskInternal(logSendBuf, logCommBuf,
						    new (std::nothrow) AXFTask());

  // TimerTask・インスタンスの生成
  m_timerTask = new (std::nothrow) AXFTimerTaskInternal();
}

bool AXFStage::init() {
  // CPU間・プロセス間送信スレッド・インスタンスの初期化
  if (NULL == AXFStage::m_commSend) {
    return false;
  }
  AXComm_t sendType = AXCOMM_CPU(AXConfig.stageComm[AXCONFIG_STAGE_DEFAULT].send.id);
  if (AXFCommSendInternal::AXCOMMSEND_SUCCESS
      != AXFStage::m_commSend->init(sendType)) {
#if 0
    /*
     * ToDo：
     * AXFCommSendクラスの実装が完了するまで、初期化に失敗しても動作させる
     */
    return false;
#endif /*  */
  }

  // CPU間・プロセス間受信スレッド・インスタンスの初期化
  if (NULL == m_commReceive) {
    return false;
  }
  AXComm_t receiveType = AXCOMM_CPU(AXConfig.stageComm[AXCONFIG_STAGE_DEFAULT].receive.id);
  if (AXFCommReceiveInternal::AXCOMMRECEIVE_SUCCESS
      != m_commReceive->init(receiveType)) {
#if 0
    /*
     * ToDo：
     * AXFCommReceiveクラスの実装が完了するまで、初期化に失敗しても動作させる
     */
    return false;
#endif /*  */
  }

  // LogTask・インスタンスの初期化
  //@UTIGN new
  if (m_logTask == NULL) {
    return false;
  }
  if (m_logTask->init() != AXFLogTaskInternal::LOG_SUCCESS) {
#if 0
    /*
     * ToDo：
     * AXFLogTaskクラスの実装が完了するまで、初期化に失敗しても動作させる
     */
    return false;
#endif
  }
  if (m_logTask->create() != AXFLogTaskInternal::LOG_SUCCESS) {
#if 0
    /*
     * ToDo：
     * AXFLogTaskクラスの実装が完了するまで、初期化に失敗しても動作させる
     */
    return false;
#endif
  }

  // TimerTask・インスタンスの初期化 (内部でタスクを生成する)
  if (m_timerTask == NULL) {
    return false;
  }
  if (m_timerTask->initAndCreate("timer", 
                                 AXCTask::AXF_PRIORITY_HIGH_DEFAULT,
                                 TIMER_TASK_STACK_SIZE)
      != AXFTimerTaskInternal::TIMER_TASK_SUCCESS) {
    return false;
  }

  return true;
}

void AXFStage::destroy() {
  m_commSend->join();
  delete m_commSend;
  m_commSend = NULL;

  m_commReceive->join();
  delete m_commReceive;
  m_commReceive = NULL;

  m_logTask->join();
  delete m_logTask;
  m_logTask = NULL;

#ifndef	UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
  delete m_timeDomain;
  m_timeDomain = NULL;
#endif	/* UNUSE_CHRONO */

  delete m_stage;
  m_stage = NULL;

  delete m_timerTask;
  m_timerTask = NULL;
}

AXFStage* AXFStage::getInstance() {
  return (m_stage);
}
