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

#ifndef AXFQUEUEINTERNAL_HPP_
#define AXFQUEUEINTERNAL_HPP_

#include "AXFEvent.hpp"

class AXFMutex;
class AXFConditionVariableInternal;
class AXFObjectName;

/**
 * @class AXFQueueInternal
 * @brief Mailbox に対し、キュー機能を提供する
 */
class AXFQueueInternal {
  struct queueBlock_t;

  struct queueBlockOrderLink_t {
    queueBlock_t* pre;
    queueBlock_t* next;
  };

  struct queueBlock_t {
    AXFEvent_t eventId;      ///< イベントID
    UINT8_t* data;               ///< 格納されているデータ
    INT32_t size;                ///< 格納されているデータのサイズ
#ifdef NEVER
    AXFObjectName sender;        ///< 送り主
    INT32_t time;///< 書き込み時刻
#endif /* NEVER */
    queueBlockOrderLink_t order;   ///< キューデータの前後のつながり
  };

  struct queueBlockLink_t { /* キューブロック */
    queueBlock_t que_bl;
  };

  AXFConditionVariableInternal* m_cond;
  AXFMutex* m_mutex;
	
 public:
  struct queueInfo_t {
    INT32_t maxCount;       ///< キュー内にはいるデータの最大数(一定)
    INT32_t maxSize;        ///< キュー内にはいるデータの最大バイト数(一定)
    INT32_t useCount;       ///< キュー内の現在格納されているデータ数
    queueBlock_t* read;     ///< キューの読み出し位置
    queueBlock_t* write;    ///< キューの書き込み位置
    UINT8_t* malloc_ptr;    ///< メモリ解放アドレス
    queueBlockLink_t* link;
  };

 protected:
  struct queuePacket_t {
    AXFEvent_t eventId;  ///< イベントID
    UINT8_t* data;           ///< データへのポインタ
    INT32_t size;            ///< データのサイズ
#ifdef NEVER
    INT32_t timeout;         ///< タイムアウトの時刻
    AXFObjectName sender;///< データの送り主の名前
    INT32_t when;///< 送り主がデータをキューイングしたシステム時刻
#endif /* NEVER */
  };

 public:
  /** @enum  queueStatus
   *  @brief Queueメソッド実行完了状態
   */
  enum queueStatus {
    QUEUE_SUCCESS = 0,      ///< 正常終了
    QUEUE_ERROR,            ///< 異常終了
    QUEUE_ERROR_PARAM,      ///< 不正なパラメータ
    QUEUE_ERROR_NOCREATE,   ///< Mailbox未生成
    QUEUE_ERROR_NOMEM,      ///< メモリ不足
    QUEUE_ERROR_MUTEX,      ///< Mutexエラー
    QUEUE_ERROR_COND,       ///< ConditionVariableエラー
  };

 private:
  queueStatus allocQueue(queueInfo_t** que);
  void freeQueue(queueInfo_t** que);
  queueStatus allocQueueBlock(queueInfo_t* que, UINT32_t count,
                              queueBlock_t** queBlk);
  void freeQueueBlock(queueInfo_t* que, queueBlock_t* que_bl);
  queueStatus allocQueueBlockData(queueInfo_t* que, UINT32_t count,
                                  UINT32_t size);
  void freeQueueBlockData(queueInfo_t* que);
  int writeQueuePacket(queueInfo_t* que, queuePacket_t* pkt);
  int readQueuePacket(queueInfo_t* que, queuePacket_t* pkt);

  inline int MIN(int x, int y) {
    return (((x) < (y)) ? (x) : (y));
  }

  // インスタンスのコピーは想定しない(Klockwork指摘対応:CL.FFM.ASSIGN)
  AXFQueueInternal& operator=(const AXFQueueInternal&) {
    return *this;
  }

  // インスタンスのコピーは想定しない(Klockwork指摘対応:CL.FFM.COPY)
  AXFQueueInternal(const AXFQueueInternal& obj)
      : m_cond(obj.m_cond),
        m_mutex(obj.m_mutex) {
  }

 public:
  /**
   * @brief AXFQueueInternalコンストラクタ
   */
  AXFQueueInternal();

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

  /**
   * @brief キューを生成する
   * @param [in] maxCount 最大データ数
   * @param [in] maxSize 最大データサイズ
   * @return キュー生成結果
   */
  virtual queueStatus createQueue(int count, int size, queueInfo_t** que,
                                  AXFConditionVariableInternal* cond,
                                  AXFMutex* mutex);

  /**
   * @brief キューを破棄する
   * @param [in] que キュー管理情報
   * @return キュー破棄結果
   */
  virtual queueStatus deleteQueue(queueInfo_t** que);

  /**
   * @brief キューへ書き込みを行う
   * @param [in] que キュー管理情報
   * @param [in] que キュー・パケット
   * @return 書き込み完了データサイズ(書き込み失敗時は 0未満の値 を返す)
   */
  virtual int writeQueue(queueInfo_t* que, queuePacket_t* pkt);

  /**
   * @brief キューから読み出しを行う
   * @param [in] que キュー管理情報
   * @param [out] que キュー・パケット
   * @return 読み出しデータサイズ
   */
  virtual int readQueue(queueInfo_t* que, queuePacket_t* pkt);

  /**
   * @brief キューに格納されている先頭データのサイズを返す
   * @param [in] que キュー管理情報
   * @return データサイズ
   */
  virtual int peekQueue(queueInfo_t* que);

  /**
   * @brief エンキューされているデータの個数を返す
   * @param [in] que キュー管理情報
   * @return データ数
   */
  virtual int npeekQueue(queueInfo_t* que);
};
#endif /* AXFQUEUEINTERNAL_HPP_ */
