#pragma once

#include "Mix/Geometry/Sphere.h"
#include "Mix/Geometry/AABB.h"
#include "Mix/Scene/IDirectionalLight.h"
#include "Mix/Private/Scene/Common/RendererObject.h"

namespace Mix{ namespace Scene{ namespace Common{

	class Camera;

	class DirectionalLight : public Mix::Scene::IDirectionalLight, public Mix::Scene::Common::RendererObject
	{
	private:
		Mix::Vector3 m_Dir;
		Mix::Vector4 m_Color;
		Mix::Scene::IDirectionalLight::PROJECTION m_Proj;

		Mix::Geometry::Sphere m_ClipBounds;
		Mix::Geometry::AABB m_CastBounds;
		Boolean m_bCast;

		Boolean m_bEnabled;

#ifdef _DEBUG
		Float32 m_DebDrawLength;
#endif //_DEBUG

	public:
		static DirectionalLight* CreateInstance( void );

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

		void Projection_CalcPSM( Mix::Scene::Common::Camera* pCamera, Mix::Matrix4x4& lightMat );
		void Projection_CalcLiSPSM( Mix::Scene::Common::Camera* pCamera, Float32 EdotL, Mix::Matrix4x4& lightMat );

		static Mix::Vector3 ComputeUpVector( const Mix::Vector3& v0, const Mix::Vector3& v1 );

	public:

#ifdef _DEBUG
		void Debug_Draw( Mix::Graphics::Utility::IPerspectiveRenderer* pPerspectiveRenderer, UInt32 flags );
#endif //_DEBUG

	public:
		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::Common::DirectionalLight
		////////////////////////////////////////////////////////////////////////////////////////////////////

		void Attach( void );
		void Detach( void );

		void Projection_Reset( Mix::Scene::Common::Camera* pCamera );

		void Projection_AppendCast( const Mix::Geometry::Sphere& bounds );
		void Projection_AppendCast( const Mix::Geometry::AABB& bounds );

		Mix::Matrix4x4 Projection_CalculateLightMatrix( Mix::Scene::Common::Camera* pCamera );

		const Mix::Geometry::Sphere& Projection_GetClipBounds( void ) const;

		Boolean Projection_IsCast( void ) const;
		const Mix::Geometry::AABB& Projection_GetCastBounds( void ) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IDirectionalLight
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual const Mix::Vector3& GetDirection( void ) const;
		virtual void SetDirection( const Mix::Vector3& dir );

		virtual const Mix::Vector4& GetColor( void ) const;
		virtual void SetColor( const Mix::Vector4& color );

		virtual const Mix::Scene::IDirectionalLight::PROJECTION& GetProjection( void ) const;
		virtual void SetProjection( const Mix::Scene::IDirectionalLight::PROJECTION& proj );

		virtual Float32 Debug_GetDrawLength( void ) const;
		virtual void Debug_SetDrawLength( Float32 len );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::ILight
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual Boolean IsEnabled( void ) const;
		virtual void SetEnabled( Boolean state );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IRendererObject
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual Mix::Scene::IRendererObject::TYPE GetType( void ) const;
		virtual Boolean IsRendering( void ) const;

	public:
		static const wchar_t* FAILED_CREATE;
	};

}}}
