/*
 * AXFDaemon.cpp
 */

#include "AXFTimeDomainInternal.hpp"
#include "AXFDaemonInternal.hpp"
#include "AXFWatchdogInternal.hpp"
#include "AXFTimerTaskInternal.hpp"
#include "AXFConditionVariableInternal.hpp"
#include "AXFMailboxInternal.hpp"
#include "AXConfig.hpp"
#include "AXScript.hpp"
#include "AX.hpp"
#include "AXFStdioInternal.hpp"
#include "AXFLuaInternal.hpp"

#include <sstream>
#include <iomanip>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const static int FIELD_SIZE_NAME = 24;
const static int FIELD_SIZE_MAILBOX_COUNT = 8;
const static int FIELD_SIZE_MAILBOX_SIZE = 8;
const static int FIELD_SIZE_PRI = 8;
const static int FIELD_SIZE_STACK = 8;
const static int FIELD_SIZE_WATCHDOG = 10;
const static int FIELD_SIZE_LIFECYCLE = 8;
const static int FIELD_SIZE_STATEMACHINE = 8;
const static int FIELD_SIZE_NPEEK = 8;
const static int FIELD_SIZE_TIME = 28;

const static std::string FIELD_LABEL_NAME("name");
const static std::string FIELD_LABEL_MAILBOX_COUNT("M:Count");
const static std::string FIELD_LABEL_MAILBOX_SIZE("M:Size");
const static std::string FIELD_LABEL_PRI("pri");
const static std::string FIELD_LABEL_STACK("stack");
const static std::string FIELD_LABEL_WATCHDOG("watchdog");
const static std::string FIELD_LABEL_LIFECYCLE("L:state");
const static std::string FIELD_LABEL_STATEMACHINE("S:state");
const static std::string FIELD_LABEL_NPEEK("M:npeek");
const static std::string FIELD_LABEL_TIME("time");

// STATE_STDIN状態の状態テーブル定義
//      {イベントID, メンバ関数ポインタ}
//      ...
//     {0,NULL}
const AXFDaemonInternal::StateTable AXFDaemonInternal::stateRunning[] = {
    { AXFDaemonInternal::EVENT_CREATE_AXM, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcCreateAxm },
    { AXFDaemonInternal::EVENT_RUN_AX, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcRunAx },
    { AXFDaemonInternal::EVENT_QUIT_AX, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcQuitAx },
    { AXFDaemonInternal::EVENT_LOG_ON, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcLogOn },
    { AXFDaemonInternal::EVENT_LOG_OFF, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcLogOff },
    { AXFDaemonInternal::EVENT_LOG_LEVEL, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcLogLevel },
    { AXFDaemonInternal::EVENT_LOGTRANS_ON, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcLogTransOn },
    { AXFDaemonInternal::EVENT_LOGTRANS_OFF, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcLogTransOff },
    { AXFDaemonInternal::EVENT_RINFO, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcRInfo },
    { AXFDaemonInternal::EVENT_INFO, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcInfo },
#ifndef UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
    { AXFDaemonInternal::EVENT_ENABLE_TIMEDOMAIN, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcEnableTimeDomain },
    { AXFDaemonInternal::EVENT_DISABLE_TIMEDOMAIN, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcDisableTimeDomain },
#endif	/* UNUSE_CHRONO */
    { AXFDaemonInternal::EVENT_BREAK_INFO, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcBreakInfo },
    { AXFDaemonInternal::EVENT_BREAK_ADD, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcBreakAdd },
#ifndef UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
    { AXFDaemonInternal::EVENT_BREAK_SETDATE, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcBreakSetdate },
    { AXFDaemonInternal::EVENT_BREAK_LIFECYCLE, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcBreakLifecycle },
    { AXFDaemonInternal::EVENT_BREAK_STATEMACHINE, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcBreakStatemachine },
    { AXFDaemonInternal::EVENT_BREAK_DEL, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcBreakDel },
    { AXFDaemonInternal::EVENT_BREAK_FORCE, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcBreakForce},
    { AXFDaemonInternal::EVENT_NEXT, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcNext },
    { AXFDaemonInternal::EVENT_SETDATE, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcSetDate },
#endif	/* UNUSE_CHRONO */
    { AXFDaemonInternal::EVENT_RUNSCRIPT, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcRunScript },
#ifdef USE_LUA
    { AXFDaemonInternal::EVENT_LUASTR, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcLuaStr },
    { AXFDaemonInternal::EVENT_LUAFILE, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcLuaFile },
#endif /* USE_LUA */
#ifndef UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
    { AXFDaemonInternal::EVENT_INTERVAL_TIMER, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcIntervalTimer },
#endif	/* UNUSE_CHRONO */
    { AXFEVENT_SYS_DOG_ACK, (AXFDaemonInternal::StateFuncPtr) &AXFDaemonInternal::funcWatchdogAck },
    { 0, NULL }
};

#ifdef	UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
AXFDaemonInternal::AXFDaemonInternal(AXFObjectName& name, AX* ax,
                                     AXFStage* stage,
                                     AXFWatchdogInternal* watchdog,
                                     AXFConditionVariableInternal* cond)
    : AXFActor(name),
      m_log(name),
      m_name(name),
      m_isCreatedAxm(false),
      m_isActiveAx(false),
      m_ax(ax),
      m_stage(stage),
      m_tokenRingTimerID(0),
      m_watchdog(watchdog),
      m_scriptCond(cond),
      m_isScript(false) {
#else	/* UNUSE_CHRONO */
AXFDaemonInternal::AXFDaemonInternal(AXFObjectName& name, AX* ax,
                                     AXFStage* stage,
                                     AXFTimeDomainInternal* timeDomain,
                                     AXFWatchdogInternal* watchdog,
                                     AXFConditionVariableInternal* cond)
    : AXFActor(name),
      m_log(name),
      m_name(name),
      m_isCreatedAxm(false),
      m_isActiveAx(false),
      m_ax(ax),
      m_stage(stage),
      m_timeDomain(timeDomain),
      m_tokenRingTimerID(0),
      m_watchdog(watchdog),
      m_scriptCond(cond),
      m_isScript(false) {
#endif	/* UNUSE_CHRONO */
  m_log.write(AXFLOG_DEBUG, "AXFDaemon Constractor");
}

AXFDaemonInternal::~AXFDaemonInternal() {
  m_log.write(AXFLOG_DEBUG, "AXFDaemon Destractor");

  delete m_watchdog;
  m_watchdog = NULL;

  delete m_scriptCond;
  m_scriptCond = NULL;
}

ax::actorFuncStatus AXFDaemonInternal::onCreate() {
  m_log.write(AXFLOG_DEBUG, "AXFDaemon onCreate()");

  // タイマ・インスタンスの生成
  if (AXFActor::TIMER_SUCCESS != createTimer()) {
    m_log.write(AXFLOG_ERR, "fail createTimer");
    return ax::AXFACTOR_ERROR;
  }

  // Watchdog の初期化
  if (NULL == m_watchdog) {
    m_log.write(AXFLOG_ERR, "fail create watchdog");
    return ax::AXFACTOR_ERROR;
  }
  if (false == m_watchdog->init(m_stage)) {
    m_log.write(AXFLOG_ERR, "fail init watchdog");
    return ax::AXFACTOR_ERROR;
  }

  // Script用条件変数の初期化
  if (NULL == m_scriptCond) {
    m_log.write(AXFLOG_ERR, "fail create Script ConditionVariable");
    return ax::AXFACTOR_ERROR;
  }
  if (m_scriptCond->init() != AXFConditionVariableInternal::COND_SUCCESS) {
    m_log.write(AXFLOG_ERR, "fail init Script ConditionVariable");
    return ax::AXFACTOR_ERROR;
  }

  // StateMachine に必要な情報を登録する
  //      自オブジェクト,
  //      初期状態,
  //      状態の最大数
  if (0 > setStateInfo(this, STATE_RUNNING, STATE_MAX)) {
    m_log.write(AXFLOG_ERR, "fail registHandle");
    return ax::AXFACTOR_ERROR;
  }

  // STATE_0状態の状態テーブルを登録する
  //      状態テーブルで登録する状態,
  //      状態テーブルのポインタ,
  setStateTable(STATE_RUNNING, stateRunning);

  // Watchdog の開始
  if (false == m_watchdog->start(m_log, *this, EVENT_INTERVAL_TIMER)) {
    return ax::AXFACTOR_ERROR;
  }

  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXFDaemonInternal::onStart() {
  m_log.write(AXFLOG_DEBUG, "AXFDaemon onStart()");

#ifndef USE_AXSHELL
  // axshell 未使用時はAXMを自動で起動させる
  const AXFLOG_LEVEL logLevel = AXFLOG_INFO;
  funcLogLevel(&logLevel, sizeof(logLevel));
  funcLogTransOn(NULL, 0);
  funcCreateAxm(NULL, 0);
  funcRunAx(NULL, 0);
#endif /* !USE_AXSHELL */

  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXFDaemonInternal::onStop() {
  m_log.write(AXFLOG_DEBUG, "AXFDaemon onStop()");

  return ax::AXFACTOR_SUCCESS;
}

#if 0
ax::actorFuncStatus AXFDaemonInternal::onPause() {
  m_log.write(AXFLOG_DEBUG, "AXFDaemon onPause()");
  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXFDaemonInternal::onResume() {
  m_log.write(AXFLOG_DEBUG, "AXFDaemon onResume()");
  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXFDaemonInternal::onRestart() {
  m_log.write(AXFLOG_DEBUG, "AXFDaemon onRestart()");
  return ax::AXFACTOR_SUCCESS;
}
#endif

ax::actorFuncStatus AXFDaemonInternal::onDestroy() {
  m_log.write(AXFLOG_DEBUG, "AXFDaemon onDestroy()");

#ifndef UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
  disableTimeDomain();
#endif

  m_watchdog->stop(m_log, *this);

  deleteTimer();

  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXFDaemonInternal::funcCreateAxm(const void* pParam,
                                                     int size) {
  ax::actorFuncStatus stat = ax::AXFACTOR_STATE_ERROR;
  std::vector<AXFStageResourceInfo> resourceInfo;
  std::vector<AXFStageStartInfo> startInfo;

  m_log.write(AXFLOG_DEBUG, "funcCreateAxm()");

  if ((NULL == AXConfig.setResourceInfo) || (NULL == AXConfig.setStartInfo)) {
    goto err;
  }
  if (true == m_isCreatedAxm) {
    m_log.write(AXFLOG_ERR, "AXM is Active already.");
    goto err;
  }

  // 1. AXM層のアクタ・リソース管理情報を作成する

  //@UTIGN (!) const
  if (false == AXConfig.setResourceInfo(resourceInfo)) {
    m_log.write(AXFLOG_ERR, "fail AXM setResourceInfo()");
    goto err;
  }

  // 2. Stage に AXM層のアクタ・リソース情報を登録する
  if (false
      == m_stage->createResource(AXFStageResource::TYPE_AXM, &resourceInfo)) {
    m_log.write(AXFLOG_ERR, "fail AXM createResource()");
    goto err;
  }

  // 3. AXM層のアクタ起動情報を作成する
  //@UTIGN (!) const
  if (false == AXConfig.setStartInfo(startInfo)) {
    m_log.write(AXFLOG_ERR, "fail AXM setStartInfo()");
    goto err;
  }

  // 4. Stage に AXM層のアクタ起動情報を登録する
  if (false == m_stage->addActors(AXFStageResource::TYPE_AXM, &startInfo)) {
    m_log.write(AXFLOG_ERR, "fail AXM addActors()");
    goto err;
  }

  m_isCreatedAxm = true;
  stat = ax::AXFACTOR_SUCCESS;

  err:

  return stat;
}

ax::actorFuncStatus AXFDaemonInternal::funcRunAx(const void* pParam, int size) {
  ax::actorFuncStatus stat = ax::AXFACTOR_STATE_ERROR;

  m_log.write(AXFLOG_DEBUG, "funcRunAx()");

  if (false == m_isCreatedAxm) {
    m_log.write(AXFLOG_ERR, "AXM is not create.");
    goto err;
  }

  if (true == m_isActiveAx) {
#ifndef	UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
    if (true == m_timeDomain->isActive()) {
      m_timeDomain->resetBreakState();
      goto end;
    } else {
      m_log.write(AXFLOG_ERR, "AX is Active already.");
      goto err;
    }
#else	/* UNUSE_CHRONO */
		m_log.write(AXFLOG_ERR, "AX is Active already.");
		goto err;
#endif	/* UNUSE_CHRONO */
  }

  // AXM層のアクタに起動要求する
  if (false == m_stage->startActors(AXFStageResource::TYPE_AXM)) {
    m_log.write(AXFLOG_ERR, "fail AXM startActors()");
    goto err;
  }

#ifndef	UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
  end:
#endif

  m_isActiveAx = true;
  stat = ax::AXFACTOR_SUCCESS;

  err:

  return stat;
}

ax::actorFuncStatus AXFDaemonInternal::funcQuitAx(const void* pParam,
                                                  int size) {
  ax::actorFuncStatus stat = ax::AXFACTOR_STATE_ERROR;

  m_log.write(AXFLOG_DEBUG, "funcQuitAx()");

  // 1. AXM層のアクタ終了とリソース解放を行う
  if (false == m_stage->exitActors(AXFStageResource::TYPE_AXM)) {
    m_log.write(AXFLOG_ERR, "fail AXM exitActors()");
    goto err;
  }

  // 2. AX へ終了要求する
  if (false == m_ax->requestQuit()) {
    m_log.write(AXFLOG_ERR, "fail AX requestQuit()");
    goto err;
  }

  stat = ax::AXFACTOR_SUCCESS;

  err:

  return stat;
}

ax::actorFuncStatus AXFDaemonInternal::funcLogOn(const void* pParam, int size) {
  m_log.write(AXFLOG_DEBUG, "funcLogOn()");
  AXFLog::isEnable = true;
  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXFDaemonInternal::funcLogOff(const void* pParam,
                                                  int size) {
  m_log.write(AXFLOG_DEBUG, "funcLogOn()");
  AXFLog::isEnable = false;
  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXFDaemonInternal::funcLogLevel(const void* pParam,
                                                    int size) {
  m_log.write(AXFLOG_DEBUG, "funcLogLevel()");
  AXFLog::m_level = *(AXFLOG_LEVEL*) pParam;
  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXFDaemonInternal::funcLogTransOn(const void* pParam,
                                                      int size) {
  m_log.write(AXFLOG_DEBUG, "funcLogTransOn()");
  AXFLog::isTrans = true;
  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXFDaemonInternal::funcLogTransOff(const void* pParam,
                                                       int size) {
  m_log.write(AXFLOG_DEBUG, "funcLogTransOn()");
  AXFLog::isTrans = false;
  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXFDaemonInternal::funcRInfo(const void* pParam, int size) {
  m_log.write(AXFLOG_DEBUG, "funcRInfo()");

  std::vector<AXFStageActorInfo>* actorInfoList = NULL;
  m_stage->getActorInfo(&actorInfoList);
  //@UTIGN (!) always not NULL
  if (NULL == actorInfoList) {
    return ax::AXFACTOR_SUCCESS;
  }

  AXFStdioInternal stdio;

  std::cout << axstdio::endl;
  stdio.flush();
  std::cout << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::left)
            << std::setw(FIELD_SIZE_NAME) << std::setfill(' ') << FIELD_LABEL_NAME
            << std::resetiosflags(std::ios::left) << std::setiosflags(std::ios::right)
            << std::setw(FIELD_SIZE_MAILBOX_COUNT) << std::setfill(' ') << FIELD_LABEL_MAILBOX_COUNT
            << std::setw(FIELD_SIZE_MAILBOX_SIZE) << std::setfill(' ') << FIELD_LABEL_MAILBOX_SIZE
            << std::setw(FIELD_SIZE_PRI) << std::setfill(' ') << FIELD_LABEL_PRI
            << std::setw(FIELD_SIZE_STACK) << std::setfill(' ') << FIELD_LABEL_STACK
            << std::setw(FIELD_SIZE_WATCHDOG) << std::setfill(' ') << FIELD_LABEL_WATCHDOG
            << axstdio::endl;
  stdio.flush();

  std::vector<AXFStageActorInfo>::iterator it = actorInfoList->begin();
  while (it != actorInfoList->end()) {
    std::cout << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::left)
              << std::setw(FIELD_SIZE_NAME) << std::setfill(' ') << (it)->name.getFullActorName()
              << std::resetiosflags(std::ios::left) << std::setiosflags(std::ios::right)
              << std::setw(FIELD_SIZE_MAILBOX_COUNT) << std::setfill(' ') << (it)->mailMaxCount
              << std::setw(FIELD_SIZE_MAILBOX_SIZE) << std::setfill(' ') << (it)->mailMaxSize
              << std::setw(FIELD_SIZE_PRI) << std::setfill(' ') << (it)->actorPriority
              << std::setw(FIELD_SIZE_STACK) << std::setfill(' ') << (it)->actorStackSize
              << std::setw(FIELD_SIZE_WATCHDOG) << std::setfill(' ') << (it)->actorWatchDogTime
              << axstdio::endl;
    stdio.flush();
    ++it;
  }
  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXFDaemonInternal::funcInfo(const void* pParam, int size) {
  m_log.write(AXFLOG_DEBUG, "funcInfo()");

  std::vector<AXFStageActorInfo>* actorInfoList = NULL;
  m_stage->getActorInfo(&actorInfoList);
  //@UTIGN (!) always not NULL
  if (NULL == actorInfoList) {
    return ax::AXFACTOR_SUCCESS;
  }

  AXFStdioInternal stdio;

  std::cout << axstdio::endl;
  stdio.flush();
  std::cout << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::left)
            << std::setw(FIELD_SIZE_NAME) << std::setfill(' ') << FIELD_LABEL_NAME
            << std::resetiosflags(std::ios::left) << std::setiosflags(std::ios::right)
            << std::setw(FIELD_SIZE_LIFECYCLE) << std::setfill(' ') << FIELD_LABEL_LIFECYCLE
            << std::setw(FIELD_SIZE_STATEMACHINE) << std::setfill(' ') << FIELD_LABEL_STATEMACHINE
            << std::setw(FIELD_SIZE_NPEEK) << std::setfill(' ') << FIELD_LABEL_NPEEK
            << std::setw(FIELD_SIZE_TIME) << std::setfill(' ') << FIELD_LABEL_TIME
            << axstdio::endl;
  stdio.flush();
  const std::string stringLifeCycleState[] = { "init", "active", "suspend",
      "inactive" };

  std::vector<AXFStageActorInfo>::iterator it = actorInfoList->begin();
  while (it != actorInfoList->end()) {
    std::cout << std::resetiosflags(std::ios::right) << std::setiosflags(std::ios::left)
              << std::setw(FIELD_SIZE_NAME) << std::setfill(' ') << (it)->name.getFullActorName();
    if (NULL != (it)->objRef) {
#ifndef	UNUSE_CHRONO	// baba Chrono非対応
      std::cout << std::resetiosflags(std::ios::left) << std::setiosflags(std::ios::right)
                << std::setw(FIELD_SIZE_LIFECYCLE) << std::setfill(' ') << stringLifeCycleState[(it)->objRef->getLifeCycleState()]
                << std::setw(FIELD_SIZE_STATEMACHINE) << std::setfill(' ') << (it)->objRef->getStateMachineState()
                << std::setw(FIELD_SIZE_NPEEK) << std::setfill(' ') << (it)->objRef->npeekMailbox()
                << std::setw(FIELD_SIZE_TIME) << std::setfill(' ') << (it)->objRef->getCurrentTime().getString();
#else	/* UNUSE_CHRONO */
      std::cout << std::resetiosflags(std::ios::left) << std::setiosflags(std::ios::right)
                << std::setw(FIELD_SIZE_LIFECYCLE) << std::setfill(' ') << stringLifeCycleState[(it)->objRef->getLifeCycleState()]
                << std::setw(FIELD_SIZE_STATEMACHINE) << std::setfill(' ') << (it)->objRef->getStateMachineState()
                << std::setw(FIELD_SIZE_NPEEK) << std::setfill(' ') << (it)->objRef->npeekMailbox();
#endif	/* UNUSE_CHRONO */
    } else {
      std::cout << std::resetiosflags(std::ios::left) << std::setiosflags(std::ios::right)
                << std::setw(FIELD_SIZE_LIFECYCLE) << std::setfill(' ') << "-"
                << std::setw(FIELD_SIZE_STATEMACHINE) << std::setfill(' ') << "-"
                << std::setw(FIELD_SIZE_NPEEK) << std::setfill(' ') << "-"
                << std::setw(FIELD_SIZE_TIME) << std::setfill(' ') << "-";
    }

    std::cout << axstdio::endl;
    stdio.flush();
    ++it;
  }
  return ax::AXFACTOR_SUCCESS;
}

#ifndef	UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
ax::actorFuncStatus AXFDaemonInternal::funcEnableTimeDomain(const void* pParam,
                                                            int size) {
  m_log.write(AXFLOG_INFO, "funcEnableTimeDomain()");

  // Watchdog を無効にする
  //@UTIGN (!) always true
  if (false == m_watchdog->stop(m_log, *this)) {
    goto err;
  }

  // TimeDomain を有効にする
  if (false == enableTimeDomain()) {
    goto err;
  }

  return ax::AXFACTOR_SUCCESS;

  err:

  return ax::AXFACTOR_ERROR;
}

ax::actorFuncStatus AXFDaemonInternal::funcDisableTimeDomain(const void* pParam,
                                                             int size) {
  m_log.write(AXFLOG_INFO, "funcDisableTimeDomain()");

  // TimeDomain を無効にする
  //@UTIGN (!) always true
  if (false == disableTimeDomain()) {
    goto err;
  }

  // Watchdog を有効にする
  if (false == m_watchdog->start(m_log, *this, EVENT_INTERVAL_TIMER)) {
    goto err;
  }

  return ax::AXFACTOR_SUCCESS;

  err:

  return ax::AXFACTOR_ERROR;
}
#endif	/* UNUSE_CHRONO */

ax::actorFuncStatus AXFDaemonInternal::funcBreakInfo(const void* pParam, int size) {
#ifndef	UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
  m_log.write(AXFLOG_INFO, "funcBreakInfo()");
  m_timeDomain->dumpBreakInfo(m_log);
#else	/* UNUSE_CHRONO */
	m_log.write(AXFLOG_INFO, "funcBreakInfo() is not supported");
#endif	/* UNUSE_CHRONO */
  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXFDaemonInternal::funcBreakAdd(const void* pParam, int size) {
#ifndef	UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
  m_log.write(AXFLOG_INFO, "funcBreakAdd()");

  AXFDaemonInternal::ParamBraekAdd* paramAdd;

  if ((size != sizeof(AXFDaemonInternal::ParamBraekAdd)) ||
      (NULL == pParam)) {
    m_log.write(AXFLOG_ERR, "illegal parameter");
    goto err;
  }

  if (false == m_timeDomain->isActive()) {
    goto err;
  }

  paramAdd = (AXFDaemonInternal::ParamBraekAdd *)pParam;
  m_timeDomain->addBreakTick(paramAdd->breakTick);
#else	/* UNUSE_CHRONO */
  m_log.write(AXFLOG_INFO, "funcBreakAdd() is not supported");
#endif	/* UNUSE_CHRONO */

  return ax::AXFACTOR_SUCCESS;

#ifndef	UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
  err:

  return ax::AXFACTOR_ERROR;
#endif
}

#ifndef UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
ax::actorFuncStatus AXFDaemonInternal::funcBreakSetdate(const void* pParam, int size) {
  m_log.write(AXFLOG_INFO, "funcBreakSetdate()");

  AXFDaemonInternal::ParamBraekSetdate* paramSetdate;
  AXFChrono chrono;

  if ((sizeof(AXFDaemonInternal::ParamBraekSetdate) != size) ||
      (NULL == pParam)) {
    m_log.write(AXFLOG_ERR, "illegal parameter");
    goto err;
  }

  if (false == m_timeDomain->isActive()) {
    goto err;
  }

  paramSetdate = (AXFDaemonInternal::ParamBraekSetdate*)pParam;
  m_timeDomain->setBreakDate(paramSetdate->breakDate);

  return ax::AXFACTOR_SUCCESS;

  err:

  return ax::AXFACTOR_ERROR;
}

ax::actorFuncStatus AXFDaemonInternal::funcBreakLifecycle(const void* pParam, int size) {
  m_log.write(AXFLOG_INFO, "funcBreakLifecycle()");

  AXFDaemonInternal::ParamBraekLifeCycle* p;

  if ((sizeof(AXFDaemonInternal::ParamBraekLifeCycle) != size) ||
      (NULL == pParam))  {
    m_log.write(AXFLOG_ERR, "illegal parameter");
    goto err;
  }

  if (false == m_timeDomain->isActive()) {
    goto err;
  }

  p = (AXFDaemonInternal::ParamBraekLifeCycle*)pParam;
  m_timeDomain->setBreakLifeCycleState(p->fullActorName, p->state, m_log);

  return ax::AXFACTOR_SUCCESS;

  err:

  return ax::AXFACTOR_ERROR;
}

ax::actorFuncStatus AXFDaemonInternal::funcBreakStatemachine(const void* pParam, int size) {
  m_log.write(AXFLOG_INFO, "funcBreakStateMachine()");

  AXFDaemonInternal::ParamBraekStateMachine* p;

  if ((sizeof(AXFDaemonInternal::ParamBraekStateMachine) != size) ||
      (NULL == pParam))  {
    m_log.write(AXFLOG_ERR, "illegal parameter");
    goto err;
  }

  if (false == m_timeDomain->isActive()) {
    goto err;
  }

  p = (AXFDaemonInternal::ParamBraekStateMachine*)pParam;
  m_timeDomain->setBreakStateMachineState(p->fullActorName, p->state, m_log);

  return ax::AXFACTOR_SUCCESS;

  err:

  return ax::AXFACTOR_ERROR;
}

ax::actorFuncStatus AXFDaemonInternal::funcBreakDel(const void* pParam, int size) {
  m_log.write(AXFLOG_INFO, "funcBreakDel()");

  AXFDaemonInternal::ParamBraekDel* paramDel;

  if ((sizeof(INT32_t) != size) ||
      (NULL == pParam)) {
    m_log.write(AXFLOG_ERR, "illegal parameter");
    goto err;
  }

  if (false == m_timeDomain->isActive()) {
    goto err;
  }

  paramDel = (AXFDaemonInternal::ParamBraekDel*)pParam;
  m_timeDomain->delBreak(paramDel->breakId, m_log);

  return ax::AXFACTOR_SUCCESS;

  err:

  return ax::AXFACTOR_ERROR;
}

ax::actorFuncStatus AXFDaemonInternal::funcBreakForce(const void* pParam, int size) {
  m_log.write(AXFLOG_INFO, "funcBreakForce()");

  if (0 != size) {
    m_log.write(AXFLOG_ERR, "illegal parameter");
    goto err;
  }

  if (false == m_timeDomain->isActive()) {
    goto err;
  }

  m_timeDomain->funcForceBreak(m_log);

  return ax::AXFACTOR_SUCCESS;

  err:

  return ax::AXFACTOR_ERROR;
}

ax::actorFuncStatus AXFDaemonInternal::funcNext(const void* pParam, int size) {
  m_log.write(AXFLOG_INFO, "funcNext()");

  if (m_timeDomain->isActive()) {
    m_timeDomain->addBreakTick(1);
    m_timeDomain->funcTokenRing(m_log);
  }
  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXFDaemonInternal::funcSetDate(const void* pParam, int size) {
  m_log.write(AXFLOG_INFO, "funcSetDate()");

  AXFChrono::TimeSpec date;
  AXFChrono chrono;

  if (sizeof(AXFChrono::TimeSpec) != size) {
    m_log.write(AXFLOG_ERR, "illegal parameter");
    goto err;
  }

  date = *(AXFChrono::TimeSpec*)pParam;
  chrono.set(date);

  if (chrono.setSystemTime() != AXFChrono::CHRONO_SUCCESS) {
    m_log.write(AXFLOG_ERR, "fail setSystemTime()");
    goto err;
  }

  //@UTIGN (!) AXFChrono::setTime() mock
  return ax::AXFACTOR_SUCCESS;

  err:

  return ax::AXFACTOR_ERROR;
}
#endif	/* UNUSE_CHRONO */

ax::actorFuncStatus AXFDaemonInternal::funcRunScript(const void* pParam, int size) {
  m_log.write(AXFLOG_INFO, "funcRunScript()");

  if (size != sizeof(INT32_t)) {
    m_log.write(AXFLOG_ERR, "illegal parameter");
    return ax::AXFACTOR_SUCCESS;
  }

  INT32_t scriptNum = *(INT32_t*)pParam;
  struct axScript_t* script;
  if ((0 <= scriptNum) && (scriptNum <= 3)) { // @ToDo: Sciript Text対応時は、任意の数のスクリプトに対応できるようにする
    script = AXConfig.scriptTable[scriptNum];
  } else {
    script = NULL;
  }

  if (NULL == script) {
    m_log.write(AXFLOG_ERR, "illegal parameter");
    return ax::AXFACTOR_SUCCESS;
  }

  runScript(script);

  return ax::AXFACTOR_SUCCESS;
}

#ifdef USE_LUA
ax::actorFuncStatus AXFDaemonInternal::funcLuaStr(const void* pParam, int size) {
  m_log.write(AXFLOG_INFO, "funcLuaStr()");

  if ((pParam == NULL) ||
      ((size <= 0) || (AXFLuaInternal::luaStrMaxSize <= static_cast<UINT32_t>(size)))){
    std::ostringstream ptrStr;
    ptrStr << std::hex << pParam;
    std::ostringstream sizeStr;
    sizeStr << size;
    m_log.write(AXFLOG_ERR, "illegal parameter: pParam=" + ptrStr.str() + " size=" + sizeStr.str());
    return ax::AXFACTOR_ERROR;
  }

  const char* cscript = (const char*)pParam;
  if ((strlen(cscript) + 1) != static_cast<size_t>(size)) {
    std::ostringstream strLenStr;
    strLenStr << strlen(cscript);
    std::ostringstream sizeStr;
    sizeStr << size;
    m_log.write(AXFLOG_ERR, "illegal parameter: strlen=" + strLenStr.str() + " size=" + sizeStr.str());
    return ax::AXFACTOR_ERROR;
  }

  AXFLuaInternal::luaStatus stat;
  AXFLuaInternal lua(this, &m_log);
  stat = lua.init();
  if (AXFLuaInternal::LUA_STATUS_OK != stat) {
    std::ostringstream statStr;
    statStr << stat;
    m_log.write(AXFLOG_ERR, "fail init Lua: stat=" + statStr.str());
    return ax::AXFACTOR_ERROR;
  }

  std::string script(cscript);
  stat = lua.doString(script);
  if (AXFLuaInternal::LUA_STATUS_OK != stat) {
    std::ostringstream statStr;
    statStr << stat;
    m_log.write(AXFLOG_ERR, "fail do Lua string: stat=" + statStr.str());
    return ax::AXFACTOR_ERROR;
  }

  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXFDaemonInternal::funcLuaFile(const void* pParam, int size) {
  m_log.write(AXFLOG_INFO, "funcLuaFile()");

  if ((pParam == NULL) ||
      ((size <= 0) || (AXFLuaInternal::luaFileNameMaxSize <= static_cast<UINT32_t>(size)))){
    std::ostringstream ptrStr;
    ptrStr << std::hex << pParam;
    std::ostringstream sizeStr;
    sizeStr << size;
    m_log.write(AXFLOG_ERR, "illegal parameter: pParam=" + ptrStr.str() + " size=" + sizeStr.str());
    return ax::AXFACTOR_ERROR;
  }

  const char* cfileName = (const char*)pParam;
  if ((strlen(cfileName) + 1) != static_cast<size_t>(size)) {
    std::ostringstream strLenStr;
    strLenStr << strlen(cfileName);
    std::ostringstream sizeStr;
    sizeStr << size;
    m_log.write(AXFLOG_ERR, "illegal parameter: strlen=" + strLenStr.str() + " size=" + sizeStr.str());
    return ax::AXFACTOR_ERROR;
  }

  AXFLuaInternal::luaStatus stat;
  AXFLuaInternal lua(this, &m_log);
  stat = lua.init();
  if (AXFLuaInternal::LUA_STATUS_OK != stat) {
    std::ostringstream statStr;
    statStr << stat;
    m_log.write(AXFLOG_ERR, "fail init Lua: stat=" + statStr.str());
    return ax::AXFACTOR_ERROR;
  }

  std::string fileName(cfileName);
  stat = lua.doFile(fileName);
  if (AXFLuaInternal::LUA_STATUS_OK != stat) {
    std::ostringstream statStr;
    statStr << stat;
    m_log.write(AXFLOG_ERR, "fail do Lua file: stat=" + statStr.str() + " filename=" + fileName);
    return ax::AXFACTOR_ERROR;
  }

  return ax::AXFACTOR_SUCCESS;
}
#endif /* USE_LUA */

#ifndef UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
ax::actorFuncStatus AXFDaemonInternal::funcIntervalTimer(const void* pParam,
                                                         int size) {
  if (m_timeDomain->isActive()) {
    m_timeDomain->funcTokenRing(m_log);
  } else {
    m_watchdog->interval(m_log);
  }
  return ax::AXFACTOR_SUCCESS;
}
#endif	/* UNUSE_CHRONO */

ax::actorFuncStatus AXFDaemonInternal::funcWatchdogAck(const void* pParam,
                                                       int size) {
  INT32_t actorId = *(INT32_t *) pParam;

#ifdef NEVER
  std::ostringstream actorIdStr;
  actorIdStr << actorId;
  m_log.write(AXFLOG_INFO, "Dog Ack id = " + actorIdStr.str());
#endif /* NEVER */

  m_watchdog->updateAckTime(m_log, actorId);

  return ax::AXFACTOR_SUCCESS;
}

#ifndef UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
bool AXFDaemonInternal::enableTimeDomain() {
  // TimeDomain を有効にする
  if (true == m_timeDomain->isActive()) {
    return true;
  }

  m_timeDomain->enable();

  // TimeDomain 用周期タイマを開始する
  AXFActor::timeSpec timer;
  timer.sec = 0;
  timer.tick = 1000;

  if (AXFActor::TIMER_SUCCESS
      != startIntervalTimer(timer, EVENT_INTERVAL_TIMER, &m_tokenRingTimerID)) {
    m_log.write(AXFLOG_ERR, "fail addIntervalTimer");
    return false;
  }

  // TimeDomain開始をTimerTaskに通知
  if (AXFStage::m_timerTask) {
    AXFStage::m_timerTask->timeDomainSwitched();
  }

  return true;
}

bool AXFDaemonInternal::disableTimeDomain() {
  // TimeDomain を無効にする
  if (false == m_timeDomain->isActive()) {
    return true;
  }
  m_timeDomain->disable();

  // TimeDomain 用周期タイマを停止する
  if (AXFActor::TIMER_SUCCESS != stopIntervalTimer(m_tokenRingTimerID)) {
    m_log.write(AXFLOG_ERR, "fail stopTimer");
  }
  m_tokenRingTimerID = 0;

  // TimeDomain終了をTimerTaskに通知
  if (AXFStage::m_timerTask) {
    AXFStage::m_timerTask->timeDomainSwitched();
  }

  return m_timeDomain->funcAllWakeup(m_log);
}
#endif	/* UNUSE_CHRONO */

void AXFDaemonInternal::scriptHandlerSignal() {
  if (false == m_isScript) {
    return;
  }

  if (AXFConditionVariableInternal::COND_SUCCESS != m_scriptCond->signal()) {
    m_log.write(AXFLOG_ERR, "script signal error");
  }
}

bool AXFDaemonInternal::isScriptMode() {
  return m_isScript;
}

void AXFDaemonInternal::runScript(struct axScript_t* script) {
  int i;

  m_isScript = true;

  for (i = 0; NULL != script[i].command.name; i++) {
    {
    AXFObjectName name(script[i].command.name);
    AXFStageActorInfo* actorInfo;
    if (0 > AXFStage::getInstance()->getActorInfo(name, &actorInfo)) {
      m_log.write(AXFLOG_ERR, "AxScript fail: get objRef " + name.getFullActorName());
      goto err;
    }

    // 該当アクタにスクリプト・ハンドラの実行要求を行う
    if (0 > actorInfo->mailRef->send(
        script[i].command.eventId,
        script[i].command.pParam,
        script[i].command.size)) {
      m_log.write(AXFLOG_ERR, "AxScript fail: send error");
      goto err;
    }

    // スクリプト・ハンドラの実行結果を待つ
    if (m_scriptCond->wait() != AXFConditionVariableInternal::COND_SUCCESS) {
      m_log.write(AXFLOG_ERR, "AxScript fail: runscript wait error");
      goto err;
    }

    // スクリプト・ハンドラ 実行結果の期待値確認
    if (actorInfo->objRef->getScriptHandlerStatus() !=
        script[i].result.handlerStatus) {
      m_log.write(AXFLOG_ERR, "AxScript fail: runscript handlerStatus error");
      goto err;
    }

    // LifeCycle状態値 の期待値確認
    if (actorInfo->objRef->getLifeCycleState() !=
        script[i].result.lifeSycleStatus) {
      m_log.write(AXFLOG_ERR, "AxScript fail: runscript lifeSycleStatus error");
      goto err;
    }

    // StateMachine状態値 の期待値確認
    if (actorInfo->objRef->getStateMachineState() !=
        script[i].result.stateMachineStatus) {
      m_log.write(AXFLOG_ERR, "AxScript fail: runscript stateMachineStatus error");
      goto err;
    }

    // @ToDo: 副作用の期待値確認

    }
  }

  m_log.write(AXFLOG_INFO, "AxScript Success");

  err:

  m_isScript = false;
}
