/**
 * @file   AXFStage.hpp
 * @brief  AXFStageクラスヘッダ
 *
 * @par    Programming Language
 *         C++
 */

#ifndef AXFSTAGE_HPP_
#define AXFSTAGE_HPP_

#include <vector>
#include "AXFObjectName.hpp"
#include "AXFActor.hpp"
#include "AXFTask.hpp"


class AXFMailboxInternal;
class AXFChrono;
class AXFTimeDomainInternal;
class AXFCommSendInternal;
class AXFCommReceiveInternal;
class AXFLogTaskInternal;
class AXFTimerTaskInternal;
class AXFDaemonInternal;

extern const int AXFSTAGE_NOTSTARTING;  // Stageからの開始処理不要（mActorInfoList[*].startOrder

/**
 * @class AXFStageResource
 * @brief Actor登録情報リソースタイプクラス
 */
class AXFStageResource {
 public:
  /** @enum  resourceType
   *  @brief リソース・タイプ
   */
  enum resourceType {
    TYPE_AXF = 0,      ///< AXF層
    TYPE_AXM,          ///< AXM層
  };
};

/**
 * @class AXFStageActorInfo
 * @brief Actor登録情報リストクラス
 *
 * @n     AXFStageクラスが管理するアクタ情報を格納するクラス
 * @n     AXFStage::getActorInfo() の出力引数に使用する
 */
class AXFStageActorInfo {
 public:
  AXFStageResource::resourceType type;
  AXFObjectName name;     ///< Actor名
  AXFActor *objRef;       ///< Actorオブジェクトリファレンス
  AXFMailboxInternal *mailRef;    ///< Actor使用メールボックスオブジェクトリファレンス
  int mailMaxCount;       ///< Actor使用Mailboxメッセージ最大数
  int mailMaxSize;        ///< Actor使用Mailboxデータ最大サイズ
  int startOrder;         ///< Actor開始要求順
  AXFTask::taskPriority actorPriority;  ///< Actorプライオリティ
  size_t actorStackSize;  ///< Actorスタックサイズ
  int actorWatchDogTime;  ///< Actorウオッチドックタイム値(ms)
#ifndef	UNUSE_CHRONO	// baba Chrono非対応のためWatchdogを動作させない
  AXFChrono watchdogAckTime;  ///< 最新Watchdog Ack時刻
#endif	/* UNUSE_CHRONO */

 public:
  /**
   * @brief AXFStageActorInfoコンストラクタ
   */
  AXFStageActorInfo()
      : type(AXFStageResource::TYPE_AXF),
        name(""),
        objRef(NULL),
        mailRef(NULL),
        mailMaxCount(0),
        mailMaxSize(0),
        startOrder(AXFSTAGE_NOTSTARTING),
        actorPriority(AXFTask::MODEL_PRIORITY_DEFAULT),
        actorStackSize(0),
        actorWatchDogTime(0) {
#ifndef	UNUSE_CHRONO	// baba Chrono非対応のためWatchdogを動作させない
    watchdogAckTime.setCounter();
#endif	/* UNUSE_CHRONO */
  }
  ;
};

/**
 * @class AXFStageResourceInfo
 * @brief Actorリソース情報クラス
 *
 * @n     AXFStageクラスへ登録するActorリソース情報を格納するクラス
 * @n     AXFStage::createResource() の入力引数に使用する
 */
class AXFStageResourceInfo {
 public:
  AXFObjectName name;     ///< Actor名
  int mailMaxCount;       ///< Actor使用Mailboxメッセージ最大数
  int mailMaxSize;        ///< Actor使用Mailboxデータ最大サイズ
  AXFTask::taskPriority actorPriority;  ///< Actorプライオリティ
  size_t actorStackSize;  ///< Actorスタックサイズ
  int actorWatchDogTime;  ///< Actorウオッチドックタイム値(ms)

 public:
  /**
   * @brief AXFStageResourceInfoコンストラクタ
   */
  AXFStageResourceInfo()
      : name(""),
        mailMaxCount(0),
        mailMaxSize(0),
        actorPriority(AXFTask::MODEL_PRIORITY_DEFAULT),
        actorStackSize(0),
        actorWatchDogTime(0) {
  }
  ;
};

/**
 * @class AXFStageStartInfo
 * @brief Actor起動情報クラス
 *
 * @n     AXFStageクラスへ登録するActor起動情報を格納するクラス
 * @n     AXFStage::addActors() の入力引数に使用する
 */
class AXFStageStartInfo {
 public:
  AXFObjectName name;     ///< Actor名
  AXFActor *objRef;       ///< Actorオブジェクトリファレンス
  int startOrder;         ///< Actor開始順位

 public:
  /**
   * @brief AXFStageStartInfoコンストラクタ
   */
  AXFStageStartInfo()
      : name(""),
        objRef(NULL),
        startOrder(AXFSTAGE_NOTSTARTING) {
  }
  ;
};

/**
 * @class AXFStage
 * @brief Stage内のリソースを格納するコンテナ機能を提供する
 */
class AXFStage {
 private:
  AXFObjectName& m_stageName;                      // 当StageNameオブジェクト
  std::vector<AXFStageActorInfo> mActorInfoList;  // Actor登録情報リスト
  std::vector<AXFMailboxInternal *> mAllMailboxRef;  // 全Actorのメールボックスオブジェクトリファレンス
  int mActorInfoListCount;                        // Actor登録数（mActorInfoList要素数）

  void sortActorInfoList();                       // Actor登録情報要素の起動順位昇順ソート
  bool getActorInfoListIndex(const AXFObjectName& actorName, int* index);  // 指定されたActorの、Actor登録リストIndexを取得する

  static AXFStage* m_stage;  // getInstanceメソッドで返すAXFStageリファレンス

 public:

  /** @enum  logRW
   *  @brief Logリード・ライト指定
   */
  enum logRW {
    LOG_READ = 0,  ///< リード指定
    LOG_WRITE,    ///< ライト指定
    LOG_RW_NUM    ///< 指定数
  };


#ifndef	UNUSE_CHRONO	// baba Chrono非対応のためAXFTimeDomainInternalは現状非対応
  /*
   * @brief  TimeDomainインスタンス
   */
  static AXFTimeDomainInternal* m_timeDomain;
#endif	/* UNUSE_CHRONO */

  /**
   * @brief  CPU間通信送信スレッド・インスタンス
   */
  static AXFCommSendInternal* m_commSend;

  /**
   * @brief  CPU間通信受信スレッド・インスタンス
   */
  static AXFCommReceiveInternal* m_commReceive;

  /**
   * @brief  AXDaemonインスタンス
   */
  static AXFDaemonInternal* m_axdaemon;

  /**
   * @brief  ログ転送スレッド・インスタンス
   */
  static AXFLogTaskInternal* m_logTask;

  /**
   * @brief  ログ転送スレッドのリード・ライト指定
   */
  static logRW isRW;

  /**
   * @brief  タイマ用スレッド・インスタンス
   */
  static AXFTimerTaskInternal* m_timerTask;

  /**
   * @brief AXFStageコンストラクタ
   *
   * @n     AXFActorを格納するコンテナを生成する
   * @param [in] stageName 生成するStage名
   */
  AXFStage(AXFObjectName& stageName);

  /**
   * @brief AXFStageデストラクタ
   */
  virtual ~AXFStage();

  /**
   * @brief Stageインスタンスを生成する
   * @param [in] stageName Stage名
   */
  static void create(AXFObjectName& stageName);

  /**
   * @brief Stageインスタンスを初期化する
   */
  static bool init();

  /**
   * @brief Stageインスタンスを破棄する
   */
  static void destroy();

  /**
   * @brief Stageインスタンスを取得する
   * @return Stageインスタンス
   */
  static AXFStage* getInstance();

  /**
   * @brief 当StageのStageNameオブジェクトリファレンスを取得する
   * @param [out] stageName 当StageNameオブジェクトリファレンス
   * @return 取得成否
   */
  bool getStageName(AXFObjectName* stageName);

  /**
   * @brief 指定されたActorが使用するリソースを生成し当Stageへ登録する
   * @param [in] type リソースタイプ
   * @param [in] actorsResourceInfo 生成リソース情報
   * @return 登録成否
   */
  virtual bool createResource(
      AXFStageResource::resourceType type,
      std::vector<AXFStageResourceInfo>* actorsResourceInfo);

  /**
   * @brief 指定されたActorの起動情報を当Stageへ登録する
   *
   * @n     本メソッドにおいて起動登録に失敗した際、
   * @n     createResource() で生成したリソースの解放を、本メソッドでは行わない
   * @n     deleteResource() を使用し、起動元責任においてリソース解放を行うこと
   *
   * @n     登録情報は以下の通り
   * -        Actor名
   * -        Actorオブジェクトリファレンス
   * -        Actor開始順位
   * @n          プライオリティではないため、ユニークとする
   * @n          ユニークでない場合、起動順序は保証しない
   * @n            AXFSTAGE_NOTSTARTING: 当Stageからの起動は不要（登録する他のActorから起動される場合に設定）
   * @n            0以上: 当Stageからの起動が必要なActor間における順位
   *
   * @param [in] type リソースタイプ
   * @param [in] actorsStartInfo Actor起動情報
   * @return 登録成否
   */
  virtual bool addActors(AXFStageResource::resourceType type,
                         std::vector<AXFStageStartInfo>* actorsStartInfo);

  /**
   * @brief 当Stageが生成した全てのリソースを解放する
   * @param [in] type リソースタイプ
   * @return 解放成否
   */
  virtual bool deleteResource(AXFStageResource::resourceType type);

  /**
   * @brief 当Stageに登録したActorにおいて、開始指示指定されたActorを順次起動する
   * @param [in] type リソースタイプ
   * @return 起動成否
   */
  virtual bool startActors(AXFStageResource::resourceType type);

  /**
   * @brief 当Stageで起動させた全Actorの処理を終了させる
   * @param [in] type リソースタイプ
   * @return 終了成否
   */
  virtual bool exitActors(AXFStageResource::resourceType type);

  /**
   * @brief Actorの全登録情報を取得する
   * @param [out] ActorInfoList Actorの登録情報（全て）
   * @return アクタID
   */
  bool getActorInfo(std::vector<AXFStageActorInfo>** actorInfoList);

  /**
   * @brief 指定されたActorの全登録情報を取得する
   * @param [in] actorName 対象とするActor名
   * @param [out] actorInfo 指定されたActorの登録情報（全て）
   * @return アクタID
   */
  int getActorInfo(const AXFObjectName& actorName,
                   AXFStageActorInfo** actorInfo);

  /**
   * @brief 指定されたActorの登録情報（Actorオブジェクトリファレンス）を取得する
   * @param [in] actorName 対象とするActor名
   * @param [out] actorObjRef 指定されたActorの登録情報（Actorオブジェクトリファレンス）
   * @return アクタID
   */
  int getActorInfo(const AXFObjectName& actorName, AXFActor** actorObjRef);

  /**
   * @brief 指定されたActorの登録情報（Mailboxオブジェクトリファレンス）を取得する
   * @param [in] actorName 対象とするActor名
   * @param [out] actorMailRef 指定されたActorの登録情報（Mailboxオブジェクトリファレンス）
   * @return アクタID
   */
  virtual int getActorInfo(const AXFObjectName& actorName,
                           AXFMailboxInternal** actorMailRef);

  /**
   * @brief 登録した全Actorのメールボックスオブジェクトリファレンスを取得する
   * @return
   * -       NULL以外：取得成功 全Actorのメールボックスオブジェクトリファレンス
   * -       NULL：取得失敗
   */
  std::vector<AXFMailboxInternal *>* getAllMailbox();
};

#endif /* AXFSTAGE_HPP_ */
