#ifndef CONNECTION_DEVICE_H
#define CONNECTION_DEVICE_H

/*!
  \file
  \brief デバイス接続のインターフェース

  \author Satofumi KAMIMURA

  $Id: connectionDevice.h 286 2008-10-20 09:40:22Z satofumi $
*/

#include "ringBufferTemplate.h"
#include <exception>
#include <string>


/*!
  \brief 通信処理のインターフェース
*/
class ConnectionDevice {
  std::string device_name;
  long baudrate_value;

  /*!
    \brief 接続

    \param device [i] 接続デバイス
    \param baudrate [i] 接続ボーレート
    \retval 0 正常終了
    \retval 戻り値 < 0 エラー
  */
  virtual int raw_connect(const char* device, long baudrate) = 0;

  /*!
    \brief 切断
  */
  virtual void raw_disconnect(void) = 0;
  virtual int raw_setBaudrate(long baudrate) = 0;

  /*!
    \brief 送信

    \param data [i] データ
    \param len [i] データサイズ
    \retval 戻り値 >= 0 送信データサイズ
    \retval 戻り値 < 0 エラー
  */
  virtual int raw_send(const char* data, int len) = 0;
  virtual void raw_flush(void) = 0;
  virtual void raw_check(int size, long timeout = 0) = 0;
  void check(int size, long timeout = 0);
  ConnectionDevice(const ConnectionDevice& rhs);

protected:
  enum { BufferSize = 4096 };
  RingBuffer<char> *recv_buffer; /*!< 受信バッファ */

public:
  enum {
    NotConnected = -2,
    DeviceOpenFail = -3,
    InvalidBaudrate = -4,
    BaudrateAdjustFail = -5,
    RecvTimeout = -6,
    LibraryInitFail = -7,
    RetryFail = -8,
    FailCheckVersion = -9,
  };

  /*!
    \brief バッファサイズ指定のコンストラクタ

    \param buffer_size [i] バッファサイズ
  */
  ConnectionDevice(int buffer_size = BufferSize-1);
  virtual ~ConnectionDevice(void);

  /*!
    \brief エラーメッセージ文字列を返す
  */
  virtual const char* what(void) = 0;

  /*!
    \brief 接続

    \param device [i] 接続デバイス
    \param baudrate [i] 接続ボーレート
    \retval 0 正常終了
    \retval 戻り値 < 0 エラー
  */
  int connect(const char* device, long baudrate);

  /*!
    \brief 切断
  */
  void disconnect(void);

  /*!
    \brief ボーレートの変更

    \param baudrate ボーレート
    \retval 0 正常終了
    \retval 戻り値 < 0 エラー
  */
  int setBaudrate(long baudrate);

  /*!
    \brief 接続済みかどうかを返す

    \retval true 接続済み
    \retval false 切断状態
  */
  virtual bool isConnected(void) = 0;

  /*!
    \brief データのフラッシュ
  */
  void flush(void);

  /*!
    \brief 送信

    \param data [i] 送信データ
    \param len [i] データサイズ
    \retval 戻り値 > 0 送信バイト数
    \retval 戻り値 < 0 エラー
  */
  int send(const char* data, int len);

  /*!
    \brief 受信

    \param data [o] 受信バッファ
    \param maxlen [i] 受信バッファの最大幅
    \param timeout [i] タイムアウト時間 [msec]
    \retval 戻り値 > 0 受信バイト数
    \retval 戻り値 < 0 エラー
  */
  virtual int recv(char* data, int maxlen, long timeout = 0);

  /*!
    \brief バッファの状態を変更せずに受信

    受信バッファの内容を減らすことなくデータを取得する

    \param data [o] 受信バッファ
    \param maxlen [i] 受信バッファの最大幅
    \retval 戻り値 > 0 受信バイト数
    \retval 戻り値 < 0 エラー
  */
  int copy(char *data, int maxlen);

  /*!
    \brief 読み出し可能なデータサイズを返す

    \retval 読み出し可能なデータサイズ
  */
  int size(void);

  /*!
    \brief 追加で受信可能なデータサイズを返す

    \retval 追加で受信可能なデータサイズ
  */
  int capacity(void);

  /*!
    \brief 接続デバイス名を返す

    \retval 接続デバイス名
  */
  const char* getDevice(void);

  /*!
    \brief 接続ボーレートを返す

    \retval 接続ボーレートを
  */
  long getBaudrate(void);
};


/*!
  \brief ConnectionDevice の例外クラス
*/
class ConnectionDevice_Exception : public std::exception {
  std::string error_message;

public:
  /*!
    \brief 接続例外のコンストラクタ

    \param message [i] 例外原因を示すエラーメッセージ
  */
  ConnectionDevice_Exception(const char* message) : error_message(message) {}
  virtual ~ConnectionDevice_Exception(void) throw () {}

  /*!
    \brief 例外原因の文字列を返す
  */
  virtual const char* what(void) const throw() {
    return error_message.c_str();
  }
};

#endif /* !CONNECTION_DEVICE_H */
