#ifndef QRK_RUNNING_H
#define QRK_RUNNING_H

/*!
  \file
  \brief 走行モジュールのインターフェース定義

  \author Satofumi KAMIMURA

  $Id: Running.h 1381 2009-10-08 19:45:31Z satofumi $
*/

#include "Position.h"
#include "Point.h"


namespace qrk
{
  class Connection;
  class Coordinate;


  //! 走行モジュールのインターフェース
  class Running
  {
  public:
    virtual ~Running(void)
    {
    }


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

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

      <strong>Example</strong>
\code
DifferentialDrive run;
if (! run.connect(device, baudrate)) {
  // 接続に失敗したときに、エラーメッセージを表示する
  printf("connect: %s\n", run.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/usb/ttyUSB0";
const long baudrate = 115200;
DifferentialDrive run;

// 指定デバイスに接続する
if (! run.connect(device, baudrate)) {
  printf("connect: %s\n", run.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 直線追従

      !!! 図

      \param[in] line 追従する直線
      \param[in] coordinate 直線を定義する座標系
    */
    virtual void followLine(const Position<long>& line,
                            const Coordinate* coordinate) = 0;

    //! \overload
    virtual void followLine(long x, long y, const Angle& angle,
                            const Coordinate* coordinate = NULL) = 0;


    /*!
      \brief 直線追従して停止

      直線追従を行い、直線の指定点に垂直な線上で停止する。

      !!! 図

      \param[in] line 追従する直線
      \param[in] coordinate 直線を定義する座標系
    */
    virtual void stopLine(const Position<long>& line,
                          const Coordinate* coordinate) = 0;

    //! \overload
    virtual void stopLine(long x, long y, const Angle& angle,
                          const Coordinate* coordinate = NULL) = 0;


    /*!
      \brief 円弧追従

      radius が正の値のときに、反時計回りに走行する。

      !!! 図

      \param[in] center 円の中心
      \param[in] radius 半径
      \param[in] coordinate 円を定義する座標系
    */
    virtual void followCircle(const Point<long>& center, long radius,
                      const Coordinate* coordinate) = 0;


    /*!
      \brief 円弧追従

      円弧追従を行い、指定された角度に垂直な線上で停止する。

      !!! 図

      \param[in] center 円の中心
      \param[in] radius 半径
      \param[in] angle 停止させる位置
      \param[in] coordinate 円を定義する座標系
    */
    virtual void stopCircle(const Point<long>& center, long radius,
                            const Angle& angle,
                            const Coordinate* coordinate) = 0;


    /*!
      \brief 指定角度だけ回転する

      angle_per_sec が正の値のときに、反時計回りに回転する。

      !!! 図

      \param[in] angle 回転角度 [Angle]
    */
    virtual void spin(const Angle& angle) = 0;


    /*!
      \brief 向きの制御

      向きを制御する。指定された向きまでの回転方向は実装依存とする。

      !!! 図

      angle に 360 [deg] 以上が指定された場合 coordinate がロボット座標系の場合は、その角度だけ回転する。coordinate がロボット座標系でない場合は、360 [deg] の剰余となる位置を向くように回転する。

      \param[in] angle 停止させる向き
      \param[in] coordinate 向きを定義する座標系
    */
    virtual void rotate(const Angle& angle, const Coordinate* coordinate) = 0;


    /*!
      \brief 停止

      等速度で停止する
    */
    virtual void stop(void) = 0;


    /*!
      \brief 推定自己位置の取得

      \return 推定自己位置
    */
    virtual Position<long> position(Coordinate* coordinate) const = 0;


    /*!
      \brief 並進の最高速度の取得

      \return 並進の最高速度 [mm / sec]
    */
    virtual long maxStraightVelocity(void) const = 0;


    /*!
      \brief 並進速度の取得

      \return 並進速度 [mm / sec]
    */
    virtual long straightVelocity(void) const = 0;


    /*!
      \brief 回転速度の取得

      \return 回転速度 [angle / sec]
    */
    virtual Angle rotateVelocity(void) const = 0;


    /*!
      \brief 位置の設定

      \param[in] coordinate 位置を指定する座標系
      \param[in] position 位置
    */
    virtual void setRobotPosition(const Position<long>& position,
                                  const Coordinate* coordinate) = 0;


    /*!
      \brief 並進速度の設定

      \param[in] mm_per_sec 並進速度 [mm / sec]
    */
    virtual void setStraightVelocity(long mm_per_sec) = 0;


    /*!
      \brief 回転速度の設定

      \param[in] angle_per_sec 回転加速度 [mm / sec]
    */
    virtual void setRotateVelocity(const Angle& angle_per_sec) = 0;


    /*!
      \brief 並進加速度の設定

      \param[in] mm_per_sec2 並進加速度 [mm / sec^2]
    */
    virtual void setStraightAcceleration(long mm_per_sec2) = 0;


    /*!
      \brief 回転加速度の設定

      \param[in] angle_per_sec2 回転加速度 [mm / sec^2]
    */
    virtual void setRotateAcceleration(const Angle& angle_per_sec2) = 0;


    /*!
      \brief 移動コマンドが安定しているかの取得

      以下の場合に true を返す。
      - 直線に追従し続ける場合に、目標直線に追従中
      - 線上で停止する場合に、線上で停止している
      - 回転し続ける場合に、目標速度に達している
      - 向きの制御中に、その方向を向いて停止している

      \retval true 制御が安定している
      \retval false 制御の途中
    */
    virtual bool isStable(void) const = 0;
  };
}

#endif /* !QRK_RUNNING_H */
