#ifndef QRK_WII_JOYSTICK_H
#define QRK_WII_JOYSTICK_H

/*!
  \file
  \brief Wii リモコン

  \attention 接続後、最初のデータが返されるまでの各メソッドの戻り値は不定となる

  \author Satofumi KAMIMURA

  $Id: WiiJoystick.h 1414 2009-10-14 23:14:02Z satofumi $

  \todo タイムスタンプのインターフェースを定義して継承すべき
*/

#include "Joystick.h"
#include "Point.h"
#include "Point3d.h"
#include <vector>
#include <memory>


namespace qrk
{
  class Angle;


  /*!
    \brief Wii リモコンの制御クラス
  */
  class WiiJoystick : public Joystick
  {
  public:
    enum {
      DefaultTimeout = 1000,    //!< タイムアウト時間

      AxisX = 0,                //!< 十字ボタンの X 軸
      AxisY = 1,                //!< 十字ボタンの Y 軸

      BUTTON_A = 0,             //!< A ボタン
      BUTTON_B,                 //!< B ボタン
      BUTTON_MINUS,             //!< &ndash; ボタン
      BUTTON_PLUS,              //!< + ボタン
      BUTTON_HOME,              //!< HOME ボタン
      BUTTON_1,                 //!< 1 ボタン
      BUTTON_2,                 //!< 2 ボタン
    };

    /*!
      \brief IR センサの情報

      位置は [0.0, 1.0] の範囲で返される
    */
    typedef struct {
      Point<double> position; //!< 位置
      size_t size;                //!< 強度
    } ir_position;


    WiiJoystick(void);
    ~WiiJoystick(void);


    /*!
      \brief Wii リモコン数の取得

      \return Wii リモコン数

      \attention 未実装
    */
    bool findController(int timeout = DefaultTimeout);

    const char* what(void) const;


    /*!
      \brief 接続

      Wii への接続を行う。

      \todo 複数の Wii リモコンに接続できるようにする
    */
    bool connect(int id = 0);

    void disconnect(void);

    bool isConnected(void) const;

    size_t axisNum(void) const;

    int axisValue(size_t index);

    size_t buttonsNum(void) const;

    bool isButtonPressed(size_t index);


    /*!
      \brief ボタンが押下回数の取得

      最後にこのメソッドが呼ばれてから、ボタンが何回押されたかを返す

      \param[in] index ボタンの番号

      \return ボタンの押下回数

      \attention 未実装
    */
    int buttonPressedTimes(size_t index);


    /*!
      \brief 加速度情報の取得

      \param[out] acceleration 加速度情報 [g]
      \param[out] timestamp データ取得時のタイムスタンプ

      \attention timestamp は未実装
    */
    void acceleration(Point3d<double>& acceleration,
                      size_t* timestamp = NULL);


    /*!
      \brief 角速度の取得

      \param[out] x_axis X 軸の角速度
      \param[out] y_axis Y 軸の角速度
      \param[out] z_axis Z 軸の角速度

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

      \attention timestamp は未実装
    */
    void rotation(Angle& x_axis, Angle& y_axis, Angle& z_axis,
                  size_t* timestamp = NULL);


    /*!
      \brief バッテリー充電率の取得

      \return バッテリーの充電率
    */
    size_t batteryPercent(void);


    /*!
      \brief IR 情報の取得

      \param[in] positions IR 検出位置、強度

    */
    bool irPosition(std::vector<ir_position>& positions);


    /*!
      \brief LED の点灯

      \param[in] led_value 下位 4 bit の 1 の箇所を点灯させる
    */
    bool setLed(unsigned char led_value);


    /*!
      \brief 振動の制御

      \param[in] rumble 振動させるとき true
    */
    bool setRumble(bool rumble);

    // !!! 音


    /*!
      \brief 加速度に対する移動平均の個数を設定

    */
    void setAccelerationAverageSize(size_t size);

  private:
    WiiJoystick(const WiiJoystick& rhs);
    WiiJoystick& operator = (const WiiJoystick& rhs);

    struct pImpl;
    const std::auto_ptr<pImpl> pimpl;
  };
}

#endif /*! QRK_WII_JOYSTICK_H */
