/*
 * AX.cpp
 */

#include "AX.hpp"
#include "AXConfig.hpp"
#include "AXFConditionVariableInternal.hpp"
#include "AXFStage.hpp"
#include "AXFActor.hpp"
#include "AXFMailboxInternal.hpp"
#include "AXFDaemonInternal.hpp"
#include "AXFShellInternal.hpp"
#include "AXFTimeDomainInternal.hpp"
#include "AXFWatchdogInternal.hpp"

#ifdef USE_OUTPUT_RESULT_XML
#include "AXFScenarioTestInternal.hpp"
#endif /* USE_OUTPUT_RESULT_XML */

#ifdef USE_GCOV_FLUSH /* need link option -lgcov */
#ifdef __cplusplus
extern "C" {
#endif
void __gcov_flush();
#ifdef __cplusplus
}
#endif
#endif /* USE_GCOV_FLUSH */

#include <new>


AX* AX::ax = NULL;
AXFConditionVariableInternal* AX::m_quitCond = NULL;
AXFObjectName* AX::m_nameAXDaemon = NULL;
AXFObjectName* AX::m_nameAXShell = NULL;

std::string axdaemonActorName("axdaemon");
std::string axshellActorName("axshell");

AX::AX() {
}

AX::~AX() {
}

bool AX::create() {
  if (NULL != ax) {
    return true;
  }

  ax = new (std::nothrow) AX();

  m_quitCond = new (std::nothrow) AXFConditionVariableInternal();

  m_nameAXDaemon = new (std::nothrow) AXFObjectName(
      axdaemonActorName, AXConfig.getStageNameObject().getStageName());

  m_nameAXShell = new (std::nothrow) AXFObjectName(
      axshellActorName, AXConfig.getStageNameObject().getStageName());

  AXFStage::create(AXConfig.getStageNameObject());
  return true;
}

bool AX::destroy() {
#ifdef USE_OUTPUT_RESULT_XML
  AXFScenarioTestInternal::makeResultXML(scenarioTestLastFilename);
#endif /* USE_OUTPUT_RESULT_XML */

#ifdef USE_GCOV_FLUSH
  __gcov_flush();
#endif /* USE_GCOV_FLUSH */

  AXFStage::destroy();

  delete m_nameAXShell;
  m_nameAXShell = NULL;

  delete m_nameAXDaemon;
  m_nameAXDaemon = NULL;

  delete m_quitCond;
  m_quitCond = NULL;

  delete ax;
  ax = NULL;

  return true;
}

AX* AX::getInstance() {
  return (ax);
}

bool AX::setInitResourceInfo(std::vector<AXFStageResourceInfo>& resourceInfo) {
  // AX初期アクタ・リソース管理情報を作成する
  AXFStageResourceInfo tmpResource;

  //   1. AXDaemon
  tmpResource.name = *m_nameAXDaemon;
  tmpResource.mailMaxCount = 20; /* Mailboxデータ最大数 (exit時に3つ必要)*/
  tmpResource.mailMaxSize = 36; /* Mailboxデータ最大サイズ (AXFDaemonInternal::ParamBraekLifeCycle) */
  tmpResource.actorPriority = AXFTask::AXF_PRIORITY_HIGH_1; /* アクタ優先度 */
#ifdef USE_LUA
  tmpResource.actorStackSize = (24 * 1024); /* アクタ・スタックサイズ */
#else
  tmpResource.actorStackSize = (3 * 1024); /* アクタ・スタックサイズ */
#endif /* USE_LUA */
  tmpResource.actorWatchDogTime = 60000; /* アクタ・ウオッチドックタイム値(ms) */
  resourceInfo.push_back(tmpResource);

#ifdef USE_AXSHELL
  //   2. AXShell
  tmpResource.name = *m_nameAXShell;
  tmpResource.mailMaxCount = 3; /* Mailboxデータ最大数 (exit時に3つ必要)*/
  tmpResource.mailMaxSize = 0; /* Mailboxデータ最大サイズ */
  tmpResource.actorPriority = AXFTask::AXF_PRIORITY_LOW_1; /* アクタ優先度 */
  tmpResource.actorStackSize = (5 * 1024); /* アクタ・スタックサイズ */
  tmpResource.actorWatchDogTime = 60000; /* アクタ・ウオッチドックタイム値(ms) */
  resourceInfo.push_back(tmpResource);
#endif /* USE_AXSHELL */
  return true;
}

bool AX::setInitStartInfo(std::vector<AXFStageStartInfo>& startInfo) {
  // AX初期アクタ・インスタンスとアクタ起動情報を作成する
  AXFStageStartInfo tmpStart;

  //   1. AXDaemon
  tmpStart.name = *m_nameAXDaemon;
#ifdef UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
  AXFDaemonInternal *axdaemon = new (std::nothrow) AXFDaemonInternal(
      *m_nameAXDaemon, AX::getInstance(), AXFStage::getInstance(),
      new (std::nothrow) AXFWatchdogInternal(),
      new (std::nothrow) AXFConditionVariableInternal());
#else	/* UNUSE_CHRONO */
  AXFDaemonInternal *axdaemon = new (std::nothrow) AXFDaemonInternal(
      *m_nameAXDaemon, AX::getInstance(), AXFStage::getInstance(),
      AXFStage::getInstance()->m_timeDomain,
      new (std::nothrow) AXFWatchdogInternal(),
      new (std::nothrow) AXFConditionVariableInternal());
#endif	/* UNUSE_CHRONO */
  //@UTIGN new
  if (NULL == axdaemon) {
    return false;
  }
  tmpStart.startOrder = 1; /* */
  tmpStart.objRef = axdaemon;
  startInfo.push_back(tmpStart);
  AXFStage::m_axdaemon = axdaemon;

  //   2. AXShell
#ifdef USE_AXSHELL
  tmpStart.name = *m_nameAXShell;
  AXFShellInternal *axshell = new (std::nothrow) AXFShellInternal(
      *m_nameAXShell);
  //@UTIGN new
  if (NULL == axshell) {
    return false;
  }
  tmpStart.startOrder = 2; /* */
  tmpStart.objRef = axshell;
  startInfo.push_back(tmpStart);
#endif /* USE_AXSHELL */

  return true;
}

bool AX::init() {
  // 1. AXコンフィグレーションのチェック
  //@UTIGN (!) const
  if ((NULL == AXConfig.getStageNameObject)
      || (NULL == AXConfig.setResourceInfo)
      || (NULL == AXConfig.setStartInfo)) {
    return false;
  }

  // 2. AXDaemon Nameインスタンスの確認
  if (NULL == m_nameAXDaemon) {
    return false;
  }

  // 3. AXShell Nameインスタンスの確認
  //@UTIGN new
  if (NULL == m_nameAXShell) {
    return false;
  }

  // 4. AX終了同期用の条件変数インスタンスの確認と初期化
  //@UTIGN new
  if (NULL == m_quitCond) {
    return false;
  }
  if (m_quitCond->init() != AXFConditionVariableInternal::COND_SUCCESS) {
    ;
  }

  // 5. Stageインスタンスの初期化
  if (false == AXFStage::init()) {
    return false;
  }

  std::vector<AXFStageResourceInfo> resourceInfo;
  setInitResourceInfo(resourceInfo);

  // 9. Stage に AXF層アクタ・リソース情報を登録する
  AXFStage::getInstance()->createResource(AXFStageResource::TYPE_AXF,
                                          &resourceInfo);

  // 10. AXF層アクタのインスタンスと起動情報を作成する
  std::vector<AXFStageStartInfo> startInfo;
  setInitStartInfo(startInfo);

  // 11. Stage に AXF層アクタ・起動情報を登録する
  AXFStage::getInstance()->addActors(AXFStageResource::TYPE_AXF, &startInfo);

  // 12. AXF層アクタを起動する
  AXFStage::getInstance()->startActors(AXFStageResource::TYPE_AXF);

  return true;
}

bool AX::waitQuit() {
  // 1. 終了要求待ち
  if (m_quitCond->wait() != AXFConditionVariableInternal::COND_SUCCESS) {
    ;
  }

  // 2. AXF層アクタの終了とリソース解放を行う
  AXFStage::getInstance()->exitActors(AXFStageResource::TYPE_AXF);

  return true;
}

bool AX::requestQuit() {
  if (AXFConditionVariableInternal::COND_SUCCESS != m_quitCond->signal()) {
    return false;
  }
  return true;
}
