#ifndef COOTRDINATE_CTRL_H
#define COOTRDINATE_CTRL_H

/*!
  \file
  \brief 座標系クラス
  
  \author Satofumi KAMIMURA
  
  $Id: coordinateCtrl.h 351 2008-11-11 22:39:03Z satofumi $
*/

#include "typeUtils.h"
#include <vector>
#include <list>
#include <string>

class ObjCoordinateCtrl;


/*!
  \brief 座標系クラス
*/
class CoordinateCtrl {
  static std::list<CoordinateCtrl*> nortify_crd;

  CoordinateCtrl* parent_crd;
  std::list<CoordinateCtrl*> child_crd;
  VXV::Position3D parent_offset;

protected:
  /*!
    \brief 座標系イベントの定義
  */
  enum {
    Create,			/*!< 座標系の追加イベント */
    Remove,			/*!< 座標系の削除イベント */
    Update,			/*!< 座標系の更新イベント */
  };

  /*!
    \brief 座標系が制御対象に貼り付けられたかを返す

    ObjCoordinateCtrl でのオーバーライド用

    \param crd [i] 座標系オブジェクトへのポインタ
    \return 制御対象に座標系を張り付けている場合 true / それ以外の場合 false
  */
  virtual bool isObjectCrdMode(const CoordinateCtrl* crd) const
  {
    static_cast<void>(crd);
    return false;
  }

  /*!
    \brief モジュールが制御対象とする物体の位置を返す

    制御対象がある場合、その位置を返す

    \return モジュールの制御対象の位置
  */
  virtual VXV::Position3D getLocalPosition(void) {
    return VXV::Position3D();
  }

  /*!
    \brief 座標系の登録を削除
  */
  virtual void remove_crd(CoordinateCtrl* crd);

  /*!
    \brief Nortify を要求するモジュールとして申告

    座標系ツリーに対し、座標系の追加、削除、座標系の相対関係の更新が行われた場合に、通知を申請するモジュールクラスがこのメソッドを呼び出す。

    \attention １つのオブジェクトで、複数回このメソッドを呼び出してはならない
  */
  void registerCrdNortifyClient(void);

  /*!
    \brief Nortify の要求を取り下げ
  */
  void unregisterCrdNortifyClient(void);

  /*!
    \brief Nortify イベントの送信
  */
  void sendCrdNortify(int event);

  /*!
    \brief Nortify イベントの通知メソッド

    座標系イベントが発生したときに、イベント通知を申請したオブジェクト毎にこのメソッドが評価される。

    \param event [i] イベントの種類
    \param crd [i] 座標系オブジェクトへのポインタ
  */
  virtual void crdNortify(int event, const CoordinateCtrl* crd)
  {
    static_cast<void>(event);
    static_cast<void>(crd);
  }

public:
  unsigned long crd_ticks; /*!< タイムスタンプ */
  VXV::Position3D crd_position; /*!< 位置データ */
  std::vector<VXV::Grid3D> crd_points; /*!< 点群データ */

  /*!
    \brief 直線
  */
  typedef struct {
    VXV::Position3D position;	/*!< 直線の始点 */
    long length;		/*!< 直線の長さ */
  } line_t;
  std::vector<line_t> crd_lines; /*!< 直線群 */
  typedef std::vector<VXV::Grid3D> polygon_t; /*!< ポリゴン定義 */
  std::vector<polygon_t> crd_polygons; /*!< ポリゴン群 */

  CoordinateCtrl(void);
  virtual ~CoordinateCtrl(void);

  /*!
    \brief 座標系の原点位置を返す

    自座標系の指定位置が、指定した座標系のどの位置に相当するかを返す

    \param crd [i] 座標系オブジェクトへのポインタ
    \param position [i] 自座標系における位置

    \return 指定座標系における、自座標系の指定位置
  */
  VXV::Position3D getCrdPosition(const CoordinateCtrl* crd = NULL,
				 const VXV::Position3D& position
				 = VXV::Position3D()) const;

  /*!
    \brief 親座標系のポインタを返す

    \return 親座標系オブジェクトへのポインタ
  */
  CoordinateCtrl* getParentCrd(void);

  /*!
    \brief ツリーのルート座標系へのポインタを返す

    \return ルート座標系オブジェクトへのポインタ
  */
  CoordinateCtrl* getRootCrd(void);

  /*!
    \brief 親座標系の設定

    指定座標系の指定位置に、自座標系の原点を定義する

    \param parent [i] 座標系オブジェクトへのポインタ
    \param offset [i] 座標系における位置
  */
  void setOwnCrdToCrd(CoordinateCtrl* parent, const VXV::Position3D&
		      offset = VXV::Position3D());

  /*!
    \brief 子座標系のポインタを格納したリストを返す

    \return 子座標系オブジェクトへのポインタを格納したリスト
  */
  std::list<CoordinateCtrl*>& getChildCrd(void);

  /*!
    \brief 親座標系のどこに原点位置を定義しているかを返す

    \return 親座標系における自座標系の原点位置
  */
  VXV::Position3D getParentCrdOffset(void);

  /*!
    \brief 親座標系に定義する原点位置を設定

    \param offset [i] 親座標系における自座標系の原点位置
  */
  void updateParentCrdOffset(const VXV::Position3D& offset);

  /*!
    \brief 座標系位置の調整

    指定座標系の指定位置と自座標系の原点位置が同じになるように、自座標系の親との相対関係を更新する

    \param crd [i] 座標系オブジェクトへのポインタ
    \param position [i] 座標系における自座標系の原点位置

    \attention 自分以下の座標系に対してこのメソッドを呼んではならない
  */
  void adjustCrdPosition(const VXV::Position3D& position,
			 const CoordinateCtrl* crd = NULL);

  /*!
    \brief モジュールが管理する制御対象に座標系を定義

    モジュールが ObjCoordinateCtrl の場合、その制御対象からの相対位置に自座標系を定義することができる。この場合、自座標系はモジュールの制御対象位置が移動する野に伴い、移動することになる。

    \param crd [i] 制御対象を持つ座標系オブジェクトへのポインタ
    \param offset [i] 座標系における位置
  */
  void setOwnCrdToObject(ObjCoordinateCtrl* crd, const VXV::Position3D&
			 offset = VXV::Position3D());
};


/*!
  \brief 座標系制御モジュールの例外
*/
class CrdCtrl_Exception : public std::exception {
  std::string error_message;

public:
  /*!
    \brief メッセージを指定して例外を投げる
  */
  CrdCtrl_Exception(const char* message) throw ()
    : error_message(message){}
  virtual ~CrdCtrl_Exception(void) throw () {}

  /*!
    \brief 例外原因の文字列を返す

    \todo 説明を記述
  */
  virtual const char* what(void) const throw() {
    return error_message.c_str();
  }
};

#endif /* !COOTRDINATE_CTRL_H */
