/*
 * AXFWatchdogInternal.cpp
 */

#include "AXFWatchdogInternal.hpp"
#include "AXConfig.hpp"
#include "AX.hpp"
#include "AXFMailboxInternal.hpp"

#include <new>

AXFObjectName* AXFWatchdogInternal::m_daemonName = NULL;

static const INT32_t intervalSec = 10;
static const INT32_t intervalTick = 0;
#ifndef	UNUSE_CHRONO	// baba Chrono非対応のためWatchdogを動作させない
static const INT64_t timeoutTick = 1000000;
#endif

AXFWatchdogInternal::AXFWatchdogInternal()
    : m_dogTimerId(0),
      m_actorInfoList(NULL) {
}

AXFWatchdogInternal::~AXFWatchdogInternal() {
  m_actorInfoList = NULL;

  delete m_daemonName;
  m_daemonName = NULL;
}

bool AXFWatchdogInternal::init(AXFStage* stage) {
  m_daemonName = new (std::nothrow) AXFObjectName(
      axdaemonActorName, AXConfig.getStageNameObject().getStageName().c_str());

  stage->getActorInfo(&m_actorInfoList);
  return true;
}

bool AXFWatchdogInternal::start(AXFLog& log, AXFActor& obj,
                                AXFEvent_t doctimeEvent) {
  if (0 != m_dogTimerId) {
    return true;
  }

  AXFActor::timeSpec timer;
  timer.sec = intervalSec;
  timer.tick = intervalTick;

  if (AXFActor::TIMER_SUCCESS
      != obj.startIntervalTimer(timer, doctimeEvent, &m_dogTimerId)) {
    log.write(AXFLOG_ERR, "fail add Watchdog Timer");
    return false;
  }

  return true;
}

bool AXFWatchdogInternal::stop(AXFLog& log, AXFActor& obj) {
  if (0 == m_dogTimerId) {
    return true;
  }

  if (AXFActor::TIMER_SUCCESS != obj.stopIntervalTimer(m_dogTimerId)) {
    log.write(AXFLOG_ERR, "fail stop Watchdog Timer");
  }
  m_dogTimerId = 0;

  return true;
}

bool AXFWatchdogInternal::interval(AXFLog& log) {
	
#ifndef	UNUSE_CHRONO	// baba Chrono非対応のためWatchdogを動作させない
  AXFChrono currentTime;
  AXFChrono lastTime;
  currentTime.setCounter();

  for (std::vector<AXFStageActorInfo>::iterator it = m_actorInfoList->begin();
      it != m_actorInfoList->end(); ++it) {
    if ((0 == (it)->name.getActorName().compare(axdaemonActorName))
        || (0 == (it)->name.getActorName().compare(axshellActorName))) {
      continue;
    }

    if ((NULL == (it)->objRef)
        || (AXFActor::AXFACTOR_STATE_ACTIVE != (it)->objRef->getLifeCycleState())) {
      continue;
    }

    lastTime = (it)->watchdogAckTime;
    lastTime.upCounter(timeoutTick);

    if (lastTime < currentTime) {
      /*
       * ToDo:
       * - Posix版
       *     タイムアウトしたアクタのコンテキスト情報をファイル出力して、
       *     プロセスを強制終了する
       *
       * - uTKernel版
       *     割り込みを全て禁止状態にして、タイムアウトしたアクタのコンテキスト情報を
       *     共有メモリに出力し、パワーOFFする。
       */
      log.write(
          AXFLOG_EMERG,
          "!!! Watchdog Timeout: name = " + (it)->name.getFullActorName());
    }

    // Watchdog 確認要求を行う
    if ((NULL == (it)->mailRef)
        || (0 > (it)->mailRef->send(AXFEVENT_SYS_DOG_REQUEST, NULL, 0))) {
          log.write(AXFLOG_ERR, "fail send AXFEVENT_SYS_DOG_REQEST");
        }
      }
#endif	/* UNUSE_CHRONO */

  return true;
}

bool AXFWatchdogInternal::ack(AXFLog& log, AXFActor& obj) {
  //@UTIGN new
  if (NULL == m_daemonName) {
    return false;
  }

  INT32_t actorId = obj.getActorId();
  if (0 > obj.send(*m_daemonName, AXFEVENT_SYS_DOG_ACK, &actorId, 4)) {
    log.write(AXFLOG_ERR, "fail send AXFEVENT_SYS_DOG_ACK");
    return false;
  }

  return true;
}

bool AXFWatchdogInternal::updateAckTime(AXFLog& log, INT32_t actorId) {
#ifndef	UNUSE_CHRONO	// baba Chrono非対応のためWatchdogを動作させない
  AXFChrono currentTime;
  currentTime.setCounter();
  (*m_actorInfoList)[actorId].watchdogAckTime = currentTime;
#endif	/* UNUSE_CHRONO */
  return true;
}
