#include "Mix/Tool/CLR/Core/Graphics/Camera.h"
#include "Mix/Tool/Win32/Core/Graphics/Camera.h"

namespace Mix{ namespace Tool{ namespace Graphics{

Camera::Camera( System::Windows::Forms::Control^ targetControl ) :
impl( new Mix::Tool::Win32::Graphics::Camera() )
{
	if( targetControl == nullptr )
	{
		throw gcnew System::ArgumentNullException( "targetControl" );
	}

	impl->Initialize( static_cast<HWND>( targetControl->Handle.ToPointer() ) );
}

Camera::~Camera( void )
{
	if( impl != nullptr )
	{
		delete impl;
		impl = nullptr;
	}
}

bool Camera::InvisibleSelection::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	return impl->GetInvisibleSelection();
}

void Camera::InvisibleSelection::set( bool value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	impl->SetInvisibleSelection( value );
}

Mix::Tool::Graphics::Camera::FillModes Camera::FillMode::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	Camera::FillModes mode;

	switch( impl->GetFillMode() )
	{
	case D3DFILL_WIREFRAME:
		mode = Camera::FillModes::Wireframe;
		break;

	case D3DFILL_SOLID:
		mode = Camera::FillModes::Solid;
		break;
	}

	return mode;
}

void Camera::FillMode::set( Mix::Tool::Graphics::Camera::FillModes value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	switch( value )
	{
	case Mix::Tool::Graphics::Camera::FillModes::Wireframe:
		impl->SetFillMode( D3DFILL_WIREFRAME );
		break;
	case Mix::Tool::Graphics::Camera::FillModes::Solid:
		impl->SetFillMode( D3DFILL_SOLID );
		break;
	}
}

Mix::Tool::Graphics::Camera::DrawTypes Camera::DrawType::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	return static_cast<Mix::Tool::Graphics::Camera::DrawTypes>( impl->GetDrawFlags() );
}

void Camera::DrawType::set( Mix::Tool::Graphics::Camera::DrawTypes value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	impl->SetDrawFlags( static_cast<unsigned int>( value ) );
}

float Camera::DefaultDistance::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	return impl->GetDefDistance();
}

void Camera::DefaultDistance::set( float value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	impl->SetDefDistance( value );
}

float Camera::Distance::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	return impl->GetDistance();
}

void Camera::Distance::set( float value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	return impl->SetDistance( value );
}

Mix::Tool::Math::Vector^ Camera::Pose::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	const D3DXQUATERNION& quat = impl->GetPose();

	return gcnew Mix::Tool::Math::Vector( quat.x, quat.y, quat.z, quat.w );
}

void Camera::Pose::set( Mix::Tool::Math::Vector^ value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	impl->SetPose( D3DXQUATERNION( value->X, value->Y, value->Z, value->W ) );
}

Mix::Tool::Math::Vector^ Camera::Target::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	const D3DXVECTOR3& temp = impl->GetTarget();

	return gcnew Mix::Tool::Math::Vector( temp.x, temp.y, temp.z, 1.0f );
}

void Camera::Target::set( Mix::Tool::Math::Vector^ value )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	if( value == nullptr )
	{
		throw gcnew System::ArgumentNullException( "Target" );
	}

	impl->SetTarget( D3DXVECTOR3( value->X, value->Y, value->Z ) );
}

Mix::Tool::Math::Vector^ Camera::LocalPosition::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	const D3DXVECTOR3& temp = impl->GetLocalPosition();

	return gcnew Mix::Tool::Math::Vector( temp.x, temp.y, temp.z, 1.0f );
}

Mix::Tool::Math::Vector^ Camera::Position::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	const D3DXVECTOR3& temp = impl->GetPosition();

	return gcnew Mix::Tool::Math::Vector( temp.x, temp.y, temp.z, 1.0f );
}

Mix::Tool::Math::Vector^ Camera::Direction::get( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	const D3DXVECTOR3& temp = impl->GetDirection();

	return gcnew Mix::Tool::Math::Vector( temp.x, temp.y, temp.z, 1.0f );
}

void Camera::Initialize( Mix::Tool::Math::Vector^ localPos, Mix::Tool::Math::Vector^ target, Mix::Tool::Math::Vector^ pose )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	D3DXVECTOR3 l( localPos->X, localPos->Y, localPos->Z );
	D3DXVECTOR3 t( target->X, target->Y, target->Z );
	D3DXQUATERNION p( pose->X, pose->Y, pose->Z, pose->W );

	impl->SetParam( l, t, p );
}

void Camera::ResetDistation( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	impl->ResetDistation();
}

void Camera::Distation( int d )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	impl->Distation( d );
}

void Camera::ResetRotation( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	impl->ResetRotation();
}

void Camera::Rotation( int h, int v )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	impl->Rotation( h, v );
}

void Camera::ResetTranslation( void )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	impl->ResetTranslation();
}

void Camera::Translation( int h, int v )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	impl->Translation( h, v );
}

void Camera::RotationLight( int h, int v )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	impl->RotationLight( h, v );
}
/*
bool Camera::SetupScalingDrawObject( System::Drawing::Point^ point )
{
	POINT temp;

	temp.x = point->X;
	temp.y = point->Y;

	return impl->SetupScalingDrawObject( temp );
}

void Camera::ScalingDrawObject( System::Drawing::Point^ point )
{
	POINT temp;

	temp.x = point->X;
	temp.y = point->Y;

	impl->ScalingDrawObject( temp );
}

void Camera::RotationDrawObject( int h, int v )
{
	impl->RotationDrawObject( h, v );
}

void Camera::TranslationDrawObject( int h, int v )
{
	impl->TranslationDrawObject( h, v );
}
*/
unsigned int Camera::SelectDrawObjectMesh( System::Drawing::Point^ point )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	POINT temp;

	temp.x = point->X;
	temp.y = point->Y;

	return impl->SelectMesh( temp );
}

Mix::Tool::Math::Vector^ Camera::Unproject( Mix::Tool::Math::Vector^ point )
{
	if( impl == NULL )
	{
		throw gcnew System::InvalidOperationException();
	}

	D3DXVECTOR3 worldPos = impl->Unproject( D3DXVECTOR3( point->X, point->Y, point->Z ) );

	return gcnew Mix::Tool::Math::Vector( worldPos.x, worldPos.y, worldPos.z, 1.0f );
}

}}}
