#pragma once

#include "Mix/Geometry/AABB.h"
#include "Mix/Geometry/Sphere.h"
#include "Mix/Private/Scene/Common/RendererTypes.h"
#include "Mix/Private/Scene/Common/OctreeTypes.h"

namespace Mix{ namespace Scene{ namespace Common{

	class Octree;
	class OctreeNode;

	class PointLight;
	class SpotLight;
	class WaterPool;
	class Planter;
	class LeavingParticle;
	class ScatterParticleUnit;
	class ActorModel;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// オクトリーオブジェクト
	////////////////////////////////////////////////////////////////////////////////////////////////////

	class OctreeObject
	{
	protected:
		virtual ~OctreeObject( void ) {}

	public:
		virtual void Refresh( void ) = 0;
		virtual void Destroy( void ) = 0;

#ifdef _DEBUG
		virtual UInt32 Debug_GetType( void ) const = 0;
		virtual void* Debug_GetInternalPtr( void ) const = 0;
#endif //_DEBUG
	};

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// リンクドオクトリーオブジェクト
	////////////////////////////////////////////////////////////////////////////////////////////////////

	template<typename THIS_TYPE>
	class LinkedOctreeObject : public Mix::Scene::Common::OctreeObject
	{
	protected:
		Mix::Scene::Common::OctreeNode* m_pNode;
		THIS_TYPE* m_pPrev;
		THIS_TYPE* m_pNext;

		Boolean m_bIllegal;

	protected:
		LinkedOctreeObject( void ) :
		m_pNode( NULL ),
		m_pPrev( NULL ),
		m_pNext( NULL ),
		m_bIllegal( False )
		{
		}

		virtual ~LinkedOctreeObject( void ) {}

	public:
		Boolean IsIllegal( void ) const { return m_bIllegal; }

		friend class Octree;
		friend class OctreeNode;
		friend class DefaultOctreeNode;
		friend class IllegalOctreeNode;
	};

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// マネージドビューオブジェクト
	////////////////////////////////////////////////////////////////////////////////////////////////////

	template<typename THIS_TYPE>
	class ManagedViewObject : public Mix::Scene::Common::LinkedOctreeObject<THIS_TYPE>
	{
	protected:
		const UInt32* m_pViewBits;

		UInt32 m_CurState;
		UInt32 m_NxtState;

	protected:
		ManagedViewObject( const UInt32* pViewBits ) :
		m_pViewBits( NULL ),
		m_CurState( 0 ),
		m_NxtState( 0 )
		{
			MIX_ASSERT( pViewBits != NULL );
			m_pViewBits = pViewBits;
		}

		virtual ~ManagedViewObject( void ) {}

	public:
		Boolean IsVisible( void ) const
		{
			return ( ( m_CurState & Mix::Scene::Common::OCTREE_VISIBLE_MASK ) != 0 );
		}

		Boolean IsVisible( UInt32 id ) const
		{
			UInt32 mask = 0x01 << ( id << 1 ); //1ビット目が視界判定
			return ( ( m_CurState & mask ) != 0 );
		}

		Boolean IsActive( void ) const
		{
			return ( m_CurState != 0 );
		}

		Boolean IsActive( UInt32 id ) const
		{
			UInt32 mask = 0x03 << ( id << 1 );	//2ビット目が影の投影
			return ( ( m_CurState & mask ) != 0 );
		}

		virtual void Invalid( Mix::Scene::Common::OCTREE_VIEW_TYPE viewType ) = 0;

		friend class OctreeView;
	};

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ローカルライトオブジェクト
	////////////////////////////////////////////////////////////////////////////////////////////////////

	class LocalLightObject : public Mix::Scene::Common::LinkedOctreeObject<Mix::Scene::Common::LocalLightObject>
	{
	protected:
		virtual ~LocalLightObject( void ) {}

	public:
		virtual Boolean IsEnabled( void ) const = 0;
		virtual const Mix::Geometry::Sphere& GetBounds( void ) const = 0;
		virtual Mix::Scene::Common::LOCAL_LIGHT* Generate( Mix::Scene::Common::LOCAL_LIGHT* pOutput ) = 0;
	};

	/*
		ポイントライト
	*/

	class PointLightObject : public Mix::Scene::Common::LocalLightObject
	{
	private:
		Mix::Scene::Common::PointLight* m_pPointLight;

	private:
		PointLightObject( Mix::Scene::Common::OctreeNode* pNode, Mix::Scene::Common::PointLight* pPointLight );
		virtual ~PointLightObject( void );

	public:
		// Mix::Scene::Common::LocalLightObject
		virtual Boolean IsEnabled( void ) const;
		virtual const Mix::Geometry::Sphere& GetBounds( void ) const;
		virtual Mix::Scene::Common::LOCAL_LIGHT* Generate( Mix::Scene::Common::LOCAL_LIGHT* pOutput );

		// Mix::Scene::Common::OctreeObject
		virtual void Refresh( void );
		virtual void Destroy( void );
#ifdef _DEBUG
		virtual UInt32 Debug_GetType( void ) const;
		virtual void* Debug_GetInternalPtr( void ) const;
#endif //_DEBUG

		friend class Octree;
	};

	/*
		スポットライト
	*/

	class SpotLightObject : public Mix::Scene::Common::LocalLightObject
	{
	private:
		Mix::Scene::Common::SpotLight* m_pSpotLight;

	private:
		SpotLightObject( Mix::Scene::Common::OctreeNode* pNode, Mix::Scene::Common::SpotLight* pSpotLight );
		virtual ~SpotLightObject( void );

	public:
		// Mix::Scene::Common::LocalLightObject
		virtual Boolean IsEnabled( void ) const;
		virtual const Mix::Geometry::Sphere& GetBounds( void ) const;
		virtual Mix::Scene::Common::LOCAL_LIGHT* Generate( Mix::Scene::Common::LOCAL_LIGHT* pOutput );

		// Mix::Scene::Common::OctreeObject
		virtual void Refresh( void );
		virtual void Destroy( void );
#ifdef _DEBUG
		virtual UInt32 Debug_GetType( void ) const;
		virtual void* Debug_GetInternalPtr( void ) const;
#endif //_DEBUG

		friend class Octree;
	};

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ウィジェット
	////////////////////////////////////////////////////////////////////////////////////////////////////

	/*
		リービングパーティクル
	*/

	class LeavingParticleObject : public Mix::Scene::Common::ManagedViewObject<Mix::Scene::Common::LeavingParticleObject>
	{
	private:
		Mix::Scene::Common::LeavingParticle* m_pContent;

	private:
		LeavingParticleObject( const UInt32* pViewBits, Mix::Scene::Common::OctreeNode* pNode, Mix::Scene::Common::LeavingParticle* pContent );
		virtual ~LeavingParticleObject( void );

	public:
		// Mix::Scene::Common::LeavingParticleObject
		const Mix::Geometry::AABB& GetBounds( void ) const;
		Mix::Scene::Common::LeavingParticle* GetContentPtr( void ) const;

		// Mix::Scene::Common::MeshObject
		virtual void Invalid( Mix::Scene::Common::OCTREE_VIEW_TYPE viewType );

		// Mix::Scene::Common::OctreeObject
		virtual void Refresh( void );
		virtual void Destroy( void );
#ifdef _DEBUG
		virtual UInt32 Debug_GetType( void ) const;
		virtual void* Debug_GetInternalPtr( void ) const;
#endif //_DEBUG

		friend class Octree;
	};

	/*
		スキャッターパーティクルユニット
	*/

	class ScatterParticleUnitObject : public Mix::Scene::Common::LinkedOctreeObject<Mix::Scene::Common::ScatterParticleUnitObject>
	{
	private:
		Mix::Scene::Common::ScatterParticleUnit* m_pContent;

	private:
		ScatterParticleUnitObject( void );
		virtual ~ScatterParticleUnitObject( void );

		void Initialize( Mix::Scene::Common::OctreeNode* pNode, Mix::Scene::Common::ScatterParticleUnit* pContent );

	public:
		/* Mix::Scene::Common::ScatterParticleUnitObject */
		const Mix::Geometry::Sphere& GetBounds( void ) const;
		Mix::Scene::Common::ScatterParticleUnit* GetContentPtr( void ) const;

		/* Mix::Scene::Common::OctreeObject */
		virtual void Refresh( void );
		virtual void Destroy( void );
#ifdef _DEBUG
		virtual UInt32 Debug_GetType( void ) const;
		virtual void* Debug_GetInternalPtr( void ) const;
#endif //_DEBUG

		friend class Octree;
	};

	/*
		プランター
	*/

	class PlanterObject : public Mix::Scene::Common::LinkedOctreeObject<Mix::Scene::Common::PlanterObject>
	{
	private:
		Mix::Scene::Common::Planter* m_pContent;
		const Mix::Geometry::AABB* m_pBounds;

	private:
		PlanterObject( Mix::Scene::Common::OctreeNode* pNode, Mix::Scene::Common::Planter* pContent );
		virtual ~PlanterObject( void );

	public:
		// Mix::Scene::Common::PlanterObject
		Boolean IsEnabled( void ) const;
		const Mix::Geometry::AABB& GetBounds( void ) const;
		Mix::Scene::Common::Planter* GetContentPtr( void ) const;

		// Mix::Scene::Common::OctreeObject
		virtual void Refresh( void );
		virtual void Destroy( void );
#ifdef _DEBUG
		virtual UInt32 Debug_GetType( void ) const;
		virtual void* Debug_GetInternalPtr( void ) const;
#endif //_DEBUG

		friend class Octree;
	};

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// モデル
	////////////////////////////////////////////////////////////////////////////////////////////////////

	/*
		アクターモデル
	*/

	class ActorModelObject : public Mix::Scene::Common::ManagedViewObject<Mix::Scene::Common::ActorModelObject>
	{
	private:
		Mix::Scene::Common::ActorModel* m_pContent;

	private:
		ActorModelObject( const UInt32* pViewBits, Mix::Scene::Common::OctreeNode* pNode, Mix::Scene::Common::ActorModel* pContent );
		virtual ~ActorModelObject( void );

	public:
		// Mix::Scene::Common::ActorModelObject
		const Mix::Geometry::Sphere& GetBounds( void ) const;
		Mix::Scene::Common::ActorModel* GetContentPtr( void ) const;

		// Mix::Scene::Common::MeshObject
		virtual void Invalid( Mix::Scene::Common::OCTREE_VIEW_TYPE viewType );

		// Mix::Scene::Common::OctreeObject
		virtual void Refresh( void );
		virtual void Destroy( void );
#ifdef _DEBUG
		virtual UInt32 Debug_GetType( void ) const;
		virtual void* Debug_GetInternalPtr( void ) const;
#endif //_DEBUG

		friend class Octree;
	};

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// その他
	////////////////////////////////////////////////////////////////////////////////////////////////////

	/*
		ウォータープールオブジェクト
	*/

	class WaterPoolObject : public Mix::Scene::Common::LinkedOctreeObject<Mix::Scene::Common::WaterPoolObject>
	{
	private:
		Mix::Scene::Common::WaterPool* m_pContent;
		Mix::Scene::IWaterPoolContext* m_pContentContext;
		const Mix::Geometry::AABB* m_pBounds;

	private:
		WaterPoolObject( Mix::Scene::Common::OctreeNode* pNode, Mix::Scene::Common::WaterPool* pContent );
		virtual ~WaterPoolObject( void );

	public:
		// Mix::Scene::Common::WaterPoolObject
		const Mix::Geometry::AABB& GetBounds( void ) const;
		Mix::Scene::Common::WaterPool* GetContentPtr( void ) const;
		Mix::Scene::IWaterPoolContext* GetContentContextPtr( void ) const;

		// Mix::Scene::Common::OctreeObject
		virtual void Refresh( void );
		virtual void Destroy( void );
#ifdef _DEBUG
		virtual UInt32 Debug_GetType( void ) const;
		virtual void* Debug_GetInternalPtr( void ) const;
#endif //_DEBUG

		friend class Octree;
	};

}}}
