#ifndef QRC_RANGE_SENSOR_H
#define QRC_RANGE_SENSOR_H

/*!
  \file
  \brief レンジ・センサーのインターフェース定義

  \author Satofumi KAMIMURA

  $Id: RangeFinder.h 1949 2011-05-06 07:18:01Z satofumi $
*/

#include "MathUtils.h"
#include <vector>
#include <cstddef>


namespace qrk
{
  class Connection;


  //! レンジ・センサーのインターフェース
  class RangeFinder
  {
  public:
    virtual ~RangeFinder(void) {}


    /*!
      \brief 内部状態を返す

      \return 内部状態を示す文字列

      <strong>Example</strong>
\code
UrgCtrl sensor;
if (! sensor.connect(device, baudrate)) {
  // 接続に失敗したときに、エラーメッセージを表示する
  printf("connect: %s\n", sensor.what());
  exit(1);
} \endcode
    */
    virtual const char* what(void) const = 0;


    /*!
      \brief 接続

      \param[in] device 接続デバイス名
      \param[in] baudrate 接続ボーレート

      \retval true 成功
      \retval false 失敗

      <strong>Example</strong>
\code
const char device[] = "/dev/ttyACM0";
const long baudrate = 115200;
UrgCtrl sensor;

// 指定デバイスに接続する
if (! sensor.connect(device, baudrate)) {
  printf("connect: %s\n", sensor.what());
  exit(1);
} \endcode
    */
    virtual bool connect(const char* device, long baudrate) = 0;


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


    /*!
      \brief 接続状態を返す

      \retval true 接続中
      \retval false 切断中
    */
    virtual bool isConnected(void) const = 0;


    /*!
      \brief 接続オブジェクトの指定

      \param[in] connection 接続オブジェクト

      \attention 内部で保持している接続オブジェクトの解放はユーザ側で保証すること
    */
    virtual void setConnection(Connection* connection) = 0;


    /*!
      \brief 接続オブジェクトの取得

      \return 接続オブジェクト
    */
    virtual Connection* connection(void) = 0;


    /*!
      \brief １周あたりのスキャン時間の取得

      \return １周あたりのスキャン時間 [msec]
    */
    virtual size_t scanMsec(void) const = 0;


    /*!
      \brief 有効距離の最小値を取得

      \return 有効距離の最小値
    */
    virtual size_t minDistance(void) const = 0;


    /*!
      \brief 有効距離の最大値を取得

      \return 有効距離の最大値
    */
    virtual size_t maxDistance(void) const = 0;


    /*!
      \brief スキャンの最大インデックスを取得

      \return スキャンの最大インデック
    */
    virtual size_t maxRange(void) const = 0;


#if 0
    /*!
      \brief タイムスタンプの登録

      センサが返すタイムスタンプの値を登録する。

      \param[in] timestamp タイムスタンプ [msec]
    */
    virtual void setTimestamp(long timestamp) = 0;
#endif


    /*!
      \brief データ取得回数の設定

      \param[in] times データの取得回数
    */
    virtual void setCaptureTimes(size_t times) = 0;


    /*!
      \brief データ取得範囲の設定

      \param[in] begin_index 取得の開始インデックス
      \param[in] end_index 取得の終了インデックス
    */
    virtual void setCaptureRange(size_t begin_index, size_t end_index) = 0;


    /*!
      \brief データの取得開始

      データの取得範囲を設定する機能は、センサ毎のクラスで提供する
    */
    virtual void requestData(void) = 0;


    /*!
      \brief 取得データの受信

      \param[out] data データの格納用
      \param[out] timestamp データ取得時のタイムスタンプ

      \retval true 正常
      \retval false エラー
    */
    virtual bool receiveData(std::vector<long>& data, long* timestamp) = 0;


    /*!
      \brief 角度に対応するインデックスの取得

      センサ前面が、0.0 [rad] に相当する。

      \param[in] radian 角度 [radian]

      \return インデックス
    */
    virtual size_t rad2index(double radian) const = 0;


    /*!
      \brief 角度に対応するインデックスの取得

      センサ前面が、0.0 [rad] に相当する。

      \param[in] degree 角度 [degree]

      \return インデックス
    */
    int deg2index(const int degree) const
    {
      return rad2index(degree * M_PI / 180.0);
    }


    /*!
      \brief インデックスに対応する角度の取得

      センサ前面が、0.0 [rad] に相当する。

      !!! 図

      \param[in] index データインデックス

      \return 角度 [radian]
    */
    virtual double index2rad(size_t index) const = 0;


    /*!
      \brief インデックスに対応する角度の取得

      センサ前面が、0.0 [rad] に相当する。

      !!! 図

      \param[in] index データインデックス

      \return 角度 [degree]
    */
    int index2deg(const int index) const
    {
      return static_cast<int>(lrint(180.0 * index2rad(index) / M_PI));
    }
  };
}
#endif /* !QRC_RANGE_SENSOR_H */
