#pragma once

//! @file Mix/Dynamics/IWorld.h
//! @brief ワールドインターフェースインクルードファイル

#include "Mix/Reference.h"
#include "Mix/Dynamics/IObject.h"
#include "Mix/Dynamics/IJoint.h"

namespace Mix{ namespace Dynamics{

	//! @class IWorld
	//! @brief ワールドインターフェース
	class IWorld : public Mix::Reference
	{
	public:
		//! @class TestCallback
		//! @brief テストコールバッククラス
		class TestCallback
		{
		public:
			//! @brief デストラクタ
			virtual ~TestCallback( void ) {}

		public:
			//! @brief オブジェクトがヒットした際に呼び出されます
			//! @param[in] pObject ヒットしたオブジェクトを表す Mix::Dynamics::IObject インターフェースのポインタ
			//! @return
			//! テストを完了する場合は True を返します<br>
			//! またテストを継続する場合は False を返します<br>
			virtual Boolean OnHit( Mix::Dynamics::IObject* pObject ) = 0;
		};

		//! @class TestWithoutSelfCallback
		//! @brief テストコールバッククラス(自身を除外)
		class TestWithoutSelfCallback : public Mix::Dynamics::IWorld::TestCallback
		{
		private:
			Mix::Dynamics::IObject* m_pSelfObject;

		public:
			//! @brief コンストラクタ
			//! @param[in] pSelfObject 自身を表す Mix::Dynamics::IObject インターフェースのポインタ
			//! @note 渡したオブジェクトの参照は保持されます
			TestWithoutSelfCallback( Mix::Dynamics::IObject* pSelfObject ) :
			m_pSelfObject( NULL )
			{
				MIX_ASSERT( pSelfObject != NULL );

				MIX_ADD_REF( pSelfObject );
				m_pSelfObject = pSelfObject;
			}

			//! @brief デストラクタ
			virtual ~TestWithoutSelfCallback( void )
			{
				MIX_RELEASE( m_pSelfObject );
			}

			//! @brief オブジェクトがヒットした際に呼び出されます
			//! @param[in] pObject ヒットしたオブジェクトを表す Mix::Dynamics::IObject インターフェースのポインタ
			//! @return 自身として渡したオブジェクトではない場合は True を返します
			virtual Boolean OnHit( Mix::Dynamics::IObject* pObject )
			{
				return ( m_pSelfObject != pObject );
			}
		};

		//! @struct TEST_RESULT
		//! @brief テスト結果構造体
		struct TEST_RESULT
		{
			Mix::Dynamics::IObject* pObject;	//!< ヒットしたオブジェクトを表す Mix::Dynamics::IObject インターフェースのポインタ

			//! @brief ヒットしたパートインデックス
			//! @note
			//! ヒットしたオブジェクトが Mix::Dynamics::IStaticMesh である場合は、<br>
			//! オブジェクトを作成する際に渡した Mix::Dynamics::MESH 構造体の配列のインデックスになります。<br>
			//! それ以外の場合は、常に -1 になります。
			Int32 partIndex;

			//! @brief ヒットしたポリゴンインデックス
			//! @note
			//! ヒットしたオブジェクトが Mix::Dynamics::IStaticMesh である場合は、<br>
			//! オブジェクトを作成する際に渡した Mix::Dynamics::MESH 構造体の配列の partIndex で指定されたパートのポリゴンのインデックスになります。
			Int32 polygonIndex;	

			Mix::Vector3 worldPos;		//!< ヒットした位置のワールド座標
			Mix::Vector3 worldNormal;	//!< ヒットした位置のワールド法線
		};

	protected:
		//! @brief デストラクタ
		virtual ~IWorld( void ){}

	public:
		//! @brief ジョイントが存在しているかどうかを取得します
		//! @param[in] pJoint ジョイントを表す Mix::Dynamics::IJoint インターフェースのポインタ
		//! @return ジョイントが存在している場合は True を返します
		virtual Boolean ContainsJoint( Mix::Dynamics::IJoint* pJoint ) const = 0;
		//! @brief ジョイントを追加します
		//! @param[in] pJoint ジョイントを表す Mix::Dynamics::IJoint インターフェースのポインタ
		//! @param[in] bCollisionDisabled 接続されているリジッドボディ同士の衝突を無効にする場合は True
		//! @return 成功した場合は True を返します
		//! @note
		//! 追加に成功した場合、ジョイントの参照カウンタを +1 します。<br>
		//! <br>
		//! ※ジョイントによって接続されているリジッドボディもワールドに追加しておく必要があります。
		virtual Boolean AddJoint( Mix::Dynamics::IJoint* pJoint, Boolean bCollisionDisabled = False ) = 0;
		//! @brief ジョイントを取り除きます
		//! @param[in] pJoint ジョイントを表す Mix::Dynamics::IJoint インターフェースのポインタ
		//! @return 成功した場合は True を返します
		//! @note 取り除きに成功した場合、ジョイントの参照カウンタを -1 します
		virtual Boolean RemoveJoint( Mix::Dynamics::IJoint* pJoint ) = 0;
		//! @brief 指定したジョイントの数を取得します
		//! @param[in] type ジョイントの種類を表す Mix::Dynamics::IJoint::TYPE 列挙定数
		//! @return ジョイントの数を返します
		virtual UInt32 GetJointCount( Mix::Dynamics::IJoint::TYPE type ) const = 0;
		//! @brief ジョイントの数を取得します
		//! @return ジョイントの数を返します
		virtual UInt32 GetTotalJointCount( void ) const = 0;

		//! @brief オブジェクトが存在しているかどうかを取得します
		//! @param[in] pObject オブジェクトを表す Mix::Dynamics::IObject インターフェースのポインタ
		//! @return オブジェクトが存在している場合は True を返します
		virtual Boolean ContainsObject( Mix::Dynamics::IObject* pObject ) const = 0;
		//! @brief オブジェクトを追加します
		//! @param[in] pObject オブジェクトを表す Mix::Dynamics::IObject インターフェースのポインタ
		//! @return 成功した場合は True を返します
		//! @note 追加に成功した場合は pObject の参照カウンタを +1 します
		virtual Boolean AddObject( Mix::Dynamics::IObject* pObject ) = 0;
		//! @brief オブジェクトを取り除きます
		//! @param[in] pObject オブジェクトを表す Mix::Dynamics::IObject インターフェースのポインタ
		//! @return 成功した場合は True を返します
		//! @note 取り除きに成功した場合、オブジェクトの参照カウンタを -1 します
		virtual Boolean RemoveObject( Mix::Dynamics::IObject* pObject ) = 0;
		//! @brief 指定したオブジェクトの数を取得します
		//! @param[in] type オブジェクトの種類を表す Mix::Dynamics::IObject::TYPE 列挙定数
		//! @return オブジェクトの数を返します
		virtual UInt32 GetObjectCount( Mix::Dynamics::IObject::TYPE type ) const = 0;
		//! @brief 全てのオブジェクトの数を取得します
		//! @return オブジェクトの数を返します
		virtual UInt32 GetTotalObjectCount( void ) const = 0;

		//! @brief 重力を取得します
		//! @return 重力を表す Mix::Vector3 クラスを返します
		virtual const Mix::Vector3& GetGravity( void ) const = 0;
		//! @brief 重力を設定します
		//! @param[in] gravity 重力を表す Mix::Vector3 クラス
		virtual void SetGravity( const Mix::Vector3& gravity ) = 0;

		//! @brief 活動状態にします
		//! @return 活動状態にできたオブジェクトの数を返します
		virtual UInt32 Activate( void ) = 0;
		//! @brief 非活動状態にします
		//! @return 非活動状態にできたオブジェクトの数を返します
		virtual UInt32 Deactivate( Boolean bForce = False ) = 0;

		//! @brief 更新します
		//! @param[in] dt 1フレームの所要時間
		//! @param[in] baseDt 1フレームの固定の所要時間
		//! @note オブジェクトに設定されているリスナーはこのタイミングで呼び出されます
		virtual void Update( Float32 dt, Float32 baseDt = 1.0f / 60.0f ) = 0;

		//! @brief 光線でテストします
		//! @param[in] fromWorldPos 光線の開始座標を表す Mix::Vector3 クラス
		//! @param[in] toWorldPos 光線の終了座標を表す Mix::Vector3 クラス
		//! @param[in] filterGroup 光線のフィルターグループ
		//! @param[in] filterMask 光線のフィルターマスク
		//! @param[in] pCallback コールバックを表す Mix::Dynamics::IWorld::TestCallback クラスのポインタ( NULL 指定可能 )
		//! @param[out] result テスト結果を表す Mix::Dynamics::IWorld::TEST_RESULT 構造体
		//! @return 交差している場合は True を返します
		virtual Boolean TestRay(	const Mix::Vector3& fromWorldPos,
									const Mix::Vector3& toWorldPos,
									UInt16 filterGroup,
									UInt16 filterMask,
									Mix::Dynamics::IWorld::TestCallback* pCallback,
									Mix::Dynamics::IWorld::TEST_RESULT& result ) = 0;

		//! @brief スウィープでテストします
		//! @param[in] pShape 交差判定をするシェイプを表す Mix::Dynamics::IShape インターフェースのポインタ
		//! @param[in] fromWorldPos スウィープの開始位置を表す  Mix::Vector3 クラス
		//! @param[in] toWorldPos スウィープの終了位置を表す  Mix::Vector3 クラス
		//! @param[in] filterGroup スウィープのフィルターグループ
		//! @param[in] filterMask スウィープのフィルターのマスク
		//! @param[in] pCallback コールバックを表す Mix::Dynamics::IWorld::TestCallback クラスのポインタ( NULL 指定可能 )
		//! @param[out] result テスト結果を表す Mix::Dynamics::IWorld::TEST_RESULT 構造体
		//! @return 交差している場合は True を返します
		virtual Boolean TestSweep(	Mix::Dynamics::IShape* pShape,
									const Mix::Vector3& fromWorldPos,
									const Mix::Vector3& toWorldPos,
									UInt16 filterGroup,
									UInt16 filterMask,
									Mix::Dynamics::IWorld::TestCallback* pCallback,
									Mix::Dynamics::IWorld::TEST_RESULT& result ) = 0;

	public:
		//! @brief デバッグ : プロファイルを取得します
		//! @return プロファイルを表す Mix::Dynamics::DEBUG_WORLD_PROFILE 構造体を返します
		virtual const Mix::Dynamics::DEBUG_WORLD_PROFILE& Debug_GetProfile( void ) const = 0;
		//! @brief デバッグ : 描画を行います
		//! @param[in] pPerspectiveRenderer デバッグ描画用のパースペクティブレンダラーを表す Mix::Graphics::Utility::IPerspectiveRenderer インターフェースのポインタ
		virtual void Debug_Draw( Mix::Graphics::Utility::IPerspectiveRenderer* pPerspectiveRenderer ) = 0;
	};

}}
