/*
 * AXFShellInternal.cpp
 */

#include "AXFShellInternal.hpp"
#include "AXFDaemonInternal.hpp"
#include "AXConfig.hpp"
#include "AX.hpp"
#include "AXFStdioInternal.hpp"
#include "AXCUtils.hpp"
#include "AXFLuaInternal.hpp"

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

const char* cmdStringHelp("help");
const char* cmdStringLogOn("logon");
const char* cmdStringLogOff("logoff");
const char* cmdStringLogLevel("log");
const char* cmdStringLogTransOn("logtranson");
const char* cmdStringLogTransOff("logtransoff");
const char* cmdStringRInfo("rinfo");
const char* cmdStringInfo("info");
const char* cmdStringCreate("create");
const char* cmdStringRun("run");
const char* cmdStringRunKeep("runkeep");
const char* cmdStringRunScript("runscript");
const char* cmdStringSetDate("setdate");
const char* cmdStringTdOn("tdon");
const char* cmdStringTdOff("tdoff");
const char* cmdStringBreak("break");
const char* cmdStringBreakInfo("info");
const char* cmdStringBreakAdd("add");
#ifndef UNUSE_CHRONO	// baba Chrono非対応
const char* cmdStringBreakSetdate("setdate");
#endif	/* UNUSE_CHRONO */
const char* cmdStringBreakLifeCycle("lc");
const char* cmdStringBreakStateMachine("sm");
const char* cmdStringBreakDel("del");
const char* cmdStringNext("next");
#ifdef USE_LUA
const char* cmdStringLuaStr("luastr");
const char* cmdStringLuaFile("luafile");
#endif /* USE_LUA */
const char* cmdStringQuit("quit");
const char* cmdStringStageName(" [StageName]");

// STATE_STDIN状態の状態テーブル定義
//      {イベントID, メンバ関数ポインタ}
//      ...
//     {0,NULL}
const AXFShellInternal::StateTable AXFShellInternal::stateStdin[] = {
    { AXFShellInternal::EVENT_STDIN, (AXFShellInternal::StateFuncPtr) &AXFShellInternal::funcStdin },
    { 0, NULL }
};

// AXShell 標準コマンド・テーブル
const AXFShellInternal::stdCmdTable_t stdCmdTable[] = {
    { cmdStringHelp, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdHelp },
    { cmdStringLogOn, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdLogOn },
    { cmdStringLogOff, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdLogOff },
    { cmdStringLogLevel, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdLogLevel },
    { cmdStringLogTransOn, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdLogTransOn },
    { cmdStringLogTransOff, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdLogTransOff },
    { cmdStringRInfo, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdRInfo },
    { cmdStringInfo, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdInfo },
    { cmdStringCreate, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdCreate },
    { cmdStringRun, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdRun },
    { cmdStringRunKeep, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdRunkeep },
    { cmdStringRunScript, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdRunScript },
#ifndef UNUSE_CHRONO	// baba Chrono非対応
    { cmdStringSetDate, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdSetDate },
#endif	/* UNUSE_CHRONO */
    { cmdStringTdOn, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdTdOn },
    { cmdStringTdOff, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdTdOff },
    { cmdStringBreak, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdBreak },
    { cmdStringNext, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdNext },
#ifdef USE_LUA
    { cmdStringLuaStr, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdLuaStr },
    { cmdStringLuaFile, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdLuaFile },
#endif /* USE_LUA */
    { cmdStringQuit, (AXFShellInternal::cmdFunc) &AXFShellInternal::cmdQuit },
    { NULL, NULL }
};

AXFShellInternal::AXFShellInternal(AXFObjectName& name)
    : AXFActor(name),
      m_log(name),
      m_name(name),
      m_lastLine(NULL) {
  m_log.write(AXFLOG_DEBUG, "AXShell Constractor");
  m_shellTable.stdCmdTable = &stdCmdTable[0];
}

AXFShellInternal::~AXFShellInternal() {
  m_log.write(AXFLOG_DEBUG, "AXShell Destractor");
  delete m_lastLine;
  m_lastLine = NULL;
}

ax::actorFuncStatus AXFShellInternal::onCreate() {
  m_log.write(AXFLOG_DEBUG, "AXShell onCreate()");

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

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

  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXFShellInternal::onStart() {
  m_log.write(AXFLOG_DEBUG, "AXShell onStart()");

  if (0 > send(m_name, EVENT_STDIN, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_STDIN");
  }

  return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXFShellInternal::onStop() {
  m_log.write(AXFLOG_DEBUG, "AXShell onStop()");
  return ax::AXFACTOR_SUCCESS;
}

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

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

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

bool AXFShellInternal::cmdHelp(std::vector<std::string>& cmdline) {
  AXFStdioInternal stdio;
  std::cout << "### Common Command ###" << axstdio::endl;
  std::cout << cmdStringLogOn << cmdStringStageName
            << "\t-- enable AXFLog [default = Self Stage]" << axstdio::endl;
  std::cout << cmdStringLogOff << cmdStringStageName
            << "\t-- disable AXFLog [default = Self Stage]" << axstdio::endl;
  std::cout << cmdStringLogLevel << " n" << cmdStringStageName
            << "\t-- set AXFLog output level (n=[0-7]) [default = Self Stage]"
            << axstdio::endl;
  std::cout << cmdStringLogTransOn << cmdStringStageName
            << "\t-- enable AXFLog transfer [default = Self Stage]"
            << axstdio::endl;
  std::cout << cmdStringLogTransOff << cmdStringStageName
            << "\t-- disable AXFLog transfer [default = Self Stage]"
            << axstdio::endl;
  std::cout << cmdStringRInfo << cmdStringStageName
            << "\t-- output Actor resource Info [default = Self Stage]"
            << axstdio::endl;
  std::cout << cmdStringInfo << cmdStringStageName
            << "\t-- output Actor Info [default = Self Stage]" << axstdio::endl;
  std::cout << cmdStringCreate << cmdStringStageName
            << "\t-- create AXM [default = Self Stage]" << axstdio::endl;
  std::cout << cmdStringRun << cmdStringStageName
            << "\t\t-- run AX [default = Self Stage]" << axstdio::endl;
  std::cout << cmdStringRunKeep
            << "\t\t\t-- runkeep AX" << axstdio::endl;
  std::cout << cmdStringRunScript << " StageName" << " [ScriptNumber]"
            << "\t-- run AxScript" << axstdio::endl;
  std::cout << cmdStringSetDate << cmdStringStageName
            << "\t-- setdate \"YYYY/MM/DD hh:mm:ss\" [default = Self Stage]" << axstdio::endl;
  std::cout << cmdStringTdOn << cmdStringStageName
            << "\t-- enable TimeDomain [default = Self Stage]" << axstdio::endl;
  std::cout << cmdStringTdOff << cmdStringStageName
            << "\t-- disable TimeDomain [default = Self Stage]" << axstdio::endl;
  std::cout << cmdStringBreak << cmdStringStageName
      << "\t-- break TimeDomain Tokenring [default = self Stage]" << axstdio::endl;
  std::cout << cmdStringBreak << " info" << cmdStringStageName
      << "\t-- output break info [default = self Stage]" << axstdio::endl;
  std::cout << cmdStringBreak << " add n(tick)" << cmdStringStageName
      << "\t-- add break Tick [default = self Stage]" << axstdio::endl;
  std::cout << cmdStringBreak << " setdate \"YYYY/MM/DD hh:mm:ss.ttttt\"" << cmdStringStageName
      << "\t-- set break Date [default = self Stage]" << axstdio::endl;
  std::cout << cmdStringBreak << " lc actor n(0:INIT, 1:ACTIVE, 2:SUSPEND, 3:INACTIVE)" << cmdStringStageName
      << "\t-- set break LifeCycle State [default = self Stage]" << axstdio::endl;
  std::cout << cmdStringBreak << " sm actor n(state machine state value)" << cmdStringStageName
      << "\t-- set break StateMachine State [default = self Stage]" << axstdio::endl;
  std::cout << cmdStringBreak << " del n(breakId)" << cmdStringStageName
      << "\t-- delete break point [default = self Stage]" << axstdio::endl;
  std::cout << cmdStringNext << cmdStringStageName
            << "\t-- run 1 step TimeDomain Tokenring [default = Self Stage]" << axstdio::endl;
#ifdef USE_LUA
  std::cout << cmdStringLuaStr << " LuaScriptString"
            << "\t-- run AX LuaScript String" << axstdio::endl;
  std::cout << cmdStringLuaFile << " LuaScriptFileName"
            << "\t-- load and run AX LuaScript File" << axstdio::endl;
#endif /* USE_LUA */
  std::cout << cmdStringQuit << cmdStringStageName
            << "\t-- quit AX [default = Self Stage]" << axstdio::endl;
  stdio.flush();

  if (AXConfig.extendCommandTable) {
    for (int i = 0; 0 != AXConfig.extendCommandTable[i].eventId; i++) {
      if (0 == i) {
        std::cout << "### Extend Command ###" << axstdio::endl;
      }
      std::cout
          << AXConfig.extendCommandTable[i].command
              + AXConfig.extendCommandTable[i].help
          << axstdio::endl;
      stdio.flush();
    }
  }

  return true;
}

bool AXFShellInternal::cmdLogOn(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "enable AXFLog");

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, 1, axdaemonActorName, isExist);
  if (false == isExist) {
    return true;
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_LOG_ON, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_LOG_ON");
  }
  return true;
}

bool AXFShellInternal::cmdLogOff(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "disable AXFLog");

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, 1, axdaemonActorName, isExist);
  if (false == isExist) {
    return true;
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_LOG_OFF, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_LOG_OFF");
  }
  return true;
}

bool AXFShellInternal::cmdLogLevel(std::vector<std::string>& cmdline) {
  int n;

  bool isExist;
  AXFObjectName axdaemonName = getDstName(cmdline, 2, axdaemonActorName,
                                          isExist);
  if (false == isExist) {
    return true;
  }

  if (cmdline.size() < 2) {
    m_log.write(AXFLOG_ERR, "illegal parameter");
    goto err;
  }

  n = atoi(cmdline[1].c_str());

  if ((AXFLOG_DEBUG > n) || (n > AXFLOG_EMERG)) {
    m_log.write(AXFLOG_ERR, "illegal parameter");
    goto err;
  }

  if (0 > send(axdaemonName, AXFDaemonInternal::EVENT_LOG_LEVEL, &n, 4)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_LOG_LEVEL");
  }
  return true;

  err:

  cmdHelp(cmdline);
  return true;
}

bool AXFShellInternal::cmdLogTransOn(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "enable AXFLog transfer");

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, 1, axdaemonActorName, isExist);
  if (false == isExist) {
    return true;
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_LOGTRANS_ON, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_LOGTRANS_ON");
  }
  return true;
}

bool AXFShellInternal::cmdLogTransOff(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "disable AXFLog transfer");

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, 1, axdaemonActorName, isExist);
  if (false == isExist) {
    return true;
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_LOGTRANS_OFF, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_LOGTRANS_OFF");
  }
  return true;
}

bool AXFShellInternal::cmdRInfo(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "output Actor resource Info");

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, 1, axdaemonActorName, isExist);
  if (false == isExist) {
    return true;
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_RINFO, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_RINFO");
  }
  return true;
}

bool AXFShellInternal::cmdInfo(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "output Actor Info");

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, 1, axdaemonActorName, isExist);
  if (false == isExist) {
    return true;
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_INFO, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_INFO");
  }
  return true;
}

bool AXFShellInternal::cmdCreate(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "create AXM");

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, 1, axdaemonActorName, isExist);
  if (false == isExist) {
    return true;
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_CREATE_AXM, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_CREATE_AXM");
  }
  return true;
}

bool AXFShellInternal::cmdRun(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "run AX");

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, 1, axdaemonActorName, isExist);
  if (false == isExist) {
    return true;
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_RUN_AX, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_RUN_AX");
  }
  return true;
}

bool AXFShellInternal::cmdRunkeep(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "run AX");

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, 1, axdaemonActorName, isExist);
  if (false == isExist) {
    return true;
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_RUN_AX, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_RUN_AX");
  }
  //tm_getcharに戻ると入力待ちとなりタスクスイッチが行えないため、
  //ここで処理を終了することで、入力待ちにもどらないようにする。
  return false;
}

bool AXFShellInternal::cmdRunScript(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "runscript");

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, 1, axdaemonActorName, isExist);
  if (false == isExist) {
    return true;
  }

  INT32_t scriptSum;
  if (cmdline.size() <= 2) {
    scriptSum = 0;
  } else {
    scriptSum = atoi(cmdline[2].c_str());
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_RUNSCRIPT, &scriptSum, sizeof(scriptSum))) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_RUNSCRIPT");
  }
  return true;
}

#ifndef UNUSE_CHRONO	// baba Chrono非対応
bool AXFShellInternal::cmdSetDate(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "setdate");

  if (2 > cmdline.size()) {
    m_log.write(AXFLOG_ERR, "illegal parameter");
    return true;
  }

  int stageIndex = 2; // AXSHELL> "setdate" "yyyy/MM/dd-hh:mm:ss.aaaaaa" "stageName"
  adjustSetdateParam(cmdline, stageIndex);

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, stageIndex, axdaemonActorName, isExist);
  if (false == isExist) {
    return true;
  }

  AXFChrono::TimeSpec date;
  AXFChrono chrono;
  if (chrono.set(cmdline[1]) != AXFChrono::CHRONO_SUCCESS) {
    m_log.write(AXFLOG_ERR, "illegal input date = " + cmdline[1]);
    return true;
  }
  date = chrono.getCounter();

  if (0 > send(dstName, AXFDaemonInternal::EVENT_SETDATE, &date, sizeof(date))) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_SETDATE");
  }
  return true;
}
#endif	/* UNUSE_CHRONO */

bool AXFShellInternal::cmdTdOn(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "enable TimeDomain");

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, 1, axdaemonActorName, isExist);
  if (false == isExist) {
    return true;
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_ENABLE_TIMEDOMAIN, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_ENABLE_TIMEDOMAIN");
  }
  return true;
}

bool AXFShellInternal::cmdTdOff(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "disable TimeDomain");

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, 1, axdaemonActorName, isExist);
  if (false == isExist) {
    return true;
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_DISABLE_TIMEDOMAIN, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_DISABLE_TIMEDOMAIN");
  }
  return true;
}

bool AXFShellInternal::cmdBreak(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "break TimeDomain tokenring");

  AXFDaemonInternal::ParamBreak paramBreak;

  int stageIndex = 2;
  AXFEvent_t event = AXFDaemonInternal::EVENT_BREAK_INFO;
  void* param = NULL;
  int pSize = 0;

  if ((2 >= cmdline.size()) && (cmdline[1] != cmdStringBreakInfo)) {
    stageIndex = 1;
    event = AXFDaemonInternal::EVENT_BREAK_FORCE;
    param = NULL;
    pSize = 0;
  } else if ((3 <= cmdline.size()) && (cmdline[1] == cmdStringBreakAdd)) {
    paramBreak.add.breakTick = atoi(cmdline[2].c_str());
    stageIndex = 3;
    event = AXFDaemonInternal::EVENT_BREAK_ADD;
    param = &paramBreak.add;
    pSize = sizeof(paramBreak.add);
#ifndef UNUSE_CHRONO	// baba Chrono非対応
  } else if ((3 <= cmdline.size()) && (cmdline[1] == cmdStringBreakSetdate)) {

    stageIndex = 3; // AXSHELL> "break" "setdate" "yyyy/MM/dd-hh:mm:ss.aaaaaa" "stageName"
    adjustSetdateParam(cmdline, stageIndex);

    AXFChrono chrono;
    if (chrono.set(cmdline[2]) != AXFChrono::CHRONO_SUCCESS) {
      m_log.write(AXFLOG_ERR, "illegal input date = " + cmdline[2]);
      return true;
    }
    paramBreak.setdate.breakDate = chrono.getCounter();
    event = AXFDaemonInternal::EVENT_BREAK_SETDATE;
    param = &paramBreak.setdate;
    pSize = sizeof(paramBreak.setdate);
#endif	/* UNUSE_CHRONO */
  } else if ((4 <= cmdline.size()) && (cmdline[1] == cmdStringBreakLifeCycle)) {
    strncpy(paramBreak.lifeCycle.fullActorName, cmdline[2].c_str(),
            sizeof(paramBreak.lifeCycle.fullActorName) - 1);
    paramBreak.lifeCycle.fullActorName[sizeof(paramBreak.lifeCycle.fullActorName) - 1] = '\0';
    paramBreak.lifeCycle.state = static_cast<AXFActor::actorState>(atoi(cmdline[3].c_str()));
    stageIndex = 4;
    event = AXFDaemonInternal::EVENT_BREAK_LIFECYCLE;
    param = &paramBreak.lifeCycle;
    pSize = sizeof(paramBreak.lifeCycle);
  } else if ((4 <= cmdline.size()) && (cmdline[1] == cmdStringBreakStateMachine)) {
    strncpy(paramBreak.stateMachine.fullActorName, cmdline[2].c_str(),
            sizeof(paramBreak.stateMachine.fullActorName) - 1);
    paramBreak.stateMachine.fullActorName[sizeof(paramBreak.stateMachine.fullActorName) - 1] = '\0';
    paramBreak.stateMachine.state = atoi(cmdline[3].c_str());
    stageIndex = 4;
    event = AXFDaemonInternal::EVENT_BREAK_STATEMACHINE;
    param = &paramBreak.stateMachine;
    pSize = sizeof(paramBreak.stateMachine);
  } else if ((3 <= cmdline.size()) && (cmdline[1] == cmdStringBreakDel)) {
    paramBreak.del.breakId = atoi(cmdline[2].c_str());
    stageIndex = 3;
    event = AXFDaemonInternal::EVENT_BREAK_DEL;
    param = &paramBreak.del;
    pSize = sizeof(paramBreak.del);
  }

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, stageIndex, axdaemonActorName, isExist);
  if (false == isExist) {
    return true;
  }

  if (0 > send(dstName, event, param, pSize)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_BREAK_*");
  }

  return true;
}

bool AXFShellInternal::cmdNext(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "next TimeDomain tokenring");

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, 1, axdaemonActorName, isExist);
  if (false == isExist) {
    return true;
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_NEXT, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_NEXT");
  }
  return true;
}

#ifdef USE_LUA
bool AXFShellInternal::cmdLuaStr(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "cmdLuaStr");

  if ((cmdline.size() < 2) ||
      (AXFLuaInternal::luaStrMaxSize) <= cmdline[1].size()) {
    m_log.write(AXFLOG_ERR, "illegal parameter");
    return true;
  }

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, 2, axdaemonActorName, isExist);
  if (false == isExist) {
    m_log.write(AXFLOG_ERR, "not found Stage");
    return true;
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_LUASTR,
               const_cast<char*>(cmdline[1].c_str()), cmdline[1].size() + 1)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_LUASTR");
  }

  return true;
}

bool AXFShellInternal::cmdLuaFile(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "cmdLuaFile");

  if ((cmdline.size() < 2) ||
      (AXFLuaInternal::luaFileNameMaxSize) <= cmdline[1].size()) {
    m_log.write(AXFLOG_ERR, "illegal parameter");
    return true;
  }

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, 2, axdaemonActorName, isExist);
  if (false == isExist) {
    m_log.write(AXFLOG_ERR, "not found Stage");
    return true;
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_LUAFILE,
               const_cast<char*>(cmdline[1].c_str()), cmdline[1].size() + 1)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_LUAFILE");
  }

  return true;
}
#endif /* USE_LUA */

bool AXFShellInternal::cmdQuit(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "quit AX");

  bool isExist;
  AXFObjectName dstName = getDstName(cmdline, 1, axdaemonActorName, isExist);
  if (false == isExist) {
    return true;
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_DISABLE_TIMEDOMAIN, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_DISABLE_TIMEDOMAIN");
    return true;
  }

  if (0 > send(dstName, AXFDaemonInternal::EVENT_QUIT_AX, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_QUIT_AX");
    return true;
  }

  if (0 == m_name.getStageName().compare(dstName.getStageName())) {
    // 自Stage終了時は標準入力待ちに戻らない
    return false;
  } else {
    return true;
  }
}

bool AXFShellInternal::cmdExtend(std::vector<std::string>& cmdline) {
  m_log.write(AXFLOG_DEBUG, "check extend command");
  bool isExtendCommand = false;
  for (int i = 0; 0 != AXConfig.extendCommandTable[i].eventId; i++) {

#ifdef NEVER
    m_log.write(AXFLOG_INFO,
                cmdline[0] + "?" + AXConfig.extendCommandTable[i].command);
#endif /* NEVER */

    if (0 == cmdline[0].compare(AXConfig.extendCommandTable[i].command)) {
      if (0
          > send(AXConfig.extendCommandTable[i].name,
                 AXConfig.extendCommandTable[i].eventId,
                 AXConfig.extendCommandTable[i].pParam,
                 AXConfig.extendCommandTable[i].size)) {
        m_log.write(AXFLOG_ERR, "fail send extend command");
      }
      isExtendCommand = true;
      break;
    }
  }
  if (false == isExtendCommand) {
    cmdHelp(cmdline);
  }
  return true;
}

bool AXFShellInternal::cmdParse(std::string& line) {
  std::vector<std::string> cmdline = AXCUtils::split(line, " ");

  bool isCondStdin = false;
  bool isFunc = false;
  for (size_t i = 0; NULL != m_shellTable.stdCmdTable[i].func; i++) {
    if (0 == cmdline[0].compare(m_shellTable.stdCmdTable[i].name)) {
      isCondStdin = (this->*m_shellTable.stdCmdTable[i].func)(cmdline);
      isFunc = true;
      break;
    }
  }

  if (false == isFunc) {
    isCondStdin = cmdExtend(cmdline);
  }

  return isCondStdin;
}

ax::actorFuncStatus AXFShellInternal::funcStdin(const void* pParam, int size) {
  m_log.write(AXFLOG_DEBUG, "AXSHell funcStdin()");

  std::string line;
  AXFStdioInternal stdio;

  std::cout << "AXShell> ";
  stdio.flush();
  line = stdio.getLine();

  bool isCondStdin = false;

  if ((NULL != m_lastLine) && (0 == line.size())) {
    isCondStdin = cmdParse(*m_lastLine);
  } else {
    isCondStdin = cmdParse(line);

    delete m_lastLine;
    m_lastLine = new (std::nothrow) std::string(line);
  }

  if (false == isCondStdin) {
    return ax::AXFACTOR_SUCCESS;
  }

  if (0 > send(m_name, EVENT_STDIN, NULL, 0)) {
    m_log.write(AXFLOG_ERR, "fail send EVENT_STDIN");
  }

  return ax::AXFACTOR_SUCCESS;
}

AXFObjectName AXFShellInternal::getDstName(std::vector<std::string>& cmdline,
                                           size_t stageIndex,
                                           std::string& actorName,
                                           bool& isExistStage) {
  std::string stageName;
  if ((cmdline.size() - 1) < stageIndex) {
    stageName = AXConfig.getStageNameObject().getStageName();
  } else {
    stageName = cmdline[stageIndex];
  }

  isExistStage = false;

  // @ToDo: ネットワーク対応時に有効なStage名の判定方法を再検討する
  if ((0 == stageName.compare("ispStage")) ||
      (0 == stageName.compare("axStage")) ||
      (0 == stageName.compare(AXConfig.getStageNameObject().getStageName()))) {
    isExistStage = true;
  }
  if (false == isExistStage) {
    m_log.write(AXFLOG_ERR, "illegal stage Name = " + stageName);
    cmdHelp(cmdline);
  }

  AXFObjectName dstName(actorName, stageName);
  return dstName;
}

void AXFShellInternal::adjustSetdateParam(std::vector<std::string>& cmdline, int& stageIndex) {
  // AXShell のパースは空白で分割するので、
  // 日付と時刻の間を空白で入力されると分割されてしまう。
  //    "yyyy/MM/dd hh:mm:ss.aaaaaa" -> "yyyy/MM/dd" "hh:mm:ss.aaaaaa"
  // 対象入力データが10文字("yyyy/mm/dd") かつ次の文字列データが
  // あるときは、分割されたとみなして、ここで連結する。
  // フォーマットのチェックは、AXFChrono::set() で行っている。

  int dateIndex = stageIndex - 1;

  if ((cmdline[dateIndex].size() == 10) && // "yyyy/mm/dd"
      ((dateIndex + 1) <= static_cast<int>(cmdline.size() - 1))) {
    cmdline[dateIndex] = cmdline[dateIndex] + "-" + cmdline[dateIndex + 1];
    stageIndex += 1; // (dateIdex + 1) は時刻データなので、ステージ名インデックスをずらす
  }
}
