#include "stdafx.h"
#include "Mix/Tool/CLR/Math/Vector.h"

namespace Mix{ namespace Tool{ namespace Math{

////////////////////////////////////////////////////////////////////////////////////////////////////
// VectorConverter
////////////////////////////////////////////////////////////////////////////////////////////////////

bool VectorConverter::CanConvertFrom( System::ComponentModel::ITypeDescriptorContext^ context, System::Type^ sourceType )
{
	if( System::String::typeid->Equals( sourceType ) == false )
	{
//		System::Diagnostics::Debug::WriteLine( L"CanConvertFrom : false" );
		return ExpandableObjectConverter::CanConvertFrom( context, sourceType );
	}

//	System::Diagnostics::Debug::WriteLine( L"CanConvertFrom : true" );

	return true;
}

System::Object^ VectorConverter::ConvertFrom( System::ComponentModel::ITypeDescriptorContext^ context, System::Globalization::CultureInfo^ culture, System::Object^ obj )
{
	if( System::String::typeid->IsInstanceOfType( obj ) == false )
	{
		return ExpandableObjectConverter::ConvertFrom( context, culture, obj );
	}

	System::String^ str = safe_cast<System::String^>( obj );

	try
	{
		array<System::String^>^ spearator = { "," };
		array<System::String^>^ tokens = str->Split( spearator, System::StringSplitOptions::None );

//		System::Diagnostics::Debug::WriteLine( L"ConvertFrom : true" );

		return gcnew Mix::Tool::Math::Vector( float::Parse( tokens[0] ), float::Parse( tokens[1] ), float::Parse( tokens[2] ) );
	}
	catch( System::Exception^ )
	{
		throw gcnew ArgumentException( L"入力フォーマットが不正です( \"x,y,z\" )" );
	}
}

bool VectorConverter::CanConvertTo( System::ComponentModel::ITypeDescriptorContext^ context, System::Type^ destinationType )
{
	if( Mix::Tool::Math::Vector::typeid->Equals( destinationType ) == false )
	{
//		System::Diagnostics::Debug::WriteLine( L"CanConvertTo : false" );
		return ExpandableObjectConverter::CanConvertTo( context, destinationType );
	}

//	System::Diagnostics::Debug::WriteLine( L"CanConvertTo : true" );

	return true;
}

System::Object^ VectorConverter::ConvertTo( System::ComponentModel::ITypeDescriptorContext^ context, System::Globalization::CultureInfo^ culture, System::Object^ value, System::Type^ destinationType )
{
	if( Mix::Tool::Math::Vector::typeid->IsInstanceOfType( value ) == false )
	{
		return ExpandableObjectConverter::ConvertTo( context, culture, value, destinationType );
	}

	Mix::Tool::Math::Vector^ vec = safe_cast<Mix::Tool::Math::Vector^>( value );
	System::String^ str = System::String::Format( L"{0},{1},{2}", vec->X, vec->Y, vec->Z );

//	System::Diagnostics::Debug::WriteLine( str );

	return str;
}

System::Object^ VectorConverter::CreateInstance( System::ComponentModel::ITypeDescriptorContext^ context, System::Collections::IDictionary^ propertyValues )
{
	try
	{
		float x = float::Parse( propertyValues[L"X"]->ToString() );
		float y = float::Parse( propertyValues[L"Y"]->ToString() );
		float z = float::Parse( propertyValues[L"Z"]->ToString() );

		return gcnew Mix::Tool::Math::Vector( x, y, z );
	}
	catch( System::Exception^ )
	{
		return nullptr;
	}
}

bool VectorConverter::GetCreateInstanceSupported( System::ComponentModel::ITypeDescriptorContext^ context )
{
//	System::Diagnostics::Debug::WriteLine( L"GetCreateInstanceSupported : " + ExpandableObjectConverter::GetCreateInstanceSupported( context ) );

	return true;
}

bool VectorConverter::GetPropertiesSupported( System::ComponentModel::ITypeDescriptorContext^ context )
{
	return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Vector
////////////////////////////////////////////////////////////////////////////////////////////////////

Vector::Vector( void ) :
x( 0.0f ),
y( 0.0f ),
z( 0.0f ),
w( 1.0f )
{
}

Vector::Vector( Vector% v ) :
x( v.x ),
y( v.y ),
z( v.z ),
w( v.w )
{
}

Vector::Vector( Vector^ v ) :
x( v->x ),
y( v->y ),
z( v->z ),
w( v->w )
{
}

Vector::Vector( Drawing::Color col )
{
	FromColor( col );
}

Vector::Vector( float _x, float _y, float _z ) :
x( _x ),
y( _y ),
z( _z ),
w( 1.0f )
{
}

Vector::Vector( float _x, float _y, float _z, float _w ) :
x( _x ),
y( _y ),
z( _z ),
w( _w )
{
}

float Vector::X::get( void )
{
	return x;
}

void Vector::X::set( float value )
{
	x = value;
}

float Vector::Y::get( void )
{
	return y;
}

void Vector::Y::set( float value )
{
	y = value;
}

float Vector::Z::get( void )
{
	return z;
}

void Vector::Z::set( float value )
{
	z = value;
}

float Vector::W::get( void )
{
	return w;
}

void Vector::W::set( float value )
{
	w = value;
}

void Vector::Normalize( void )
{
	float len = ::sqrtf( x * x + y * y + z * z + w * w );

	if( MIX_FLOAT_IS_ZERO( len ) == false )
	{
		float invLen = 1.0f / len;

		x *= invLen;
		y *= invLen;
		z *= invLen;
		w *= invLen;

		if( MIX_FLOAT_IS_ZERO( w ) == false )
		{
			float invW = 1.0f / w;

			x *= w;
			y *= w;
			z *= w;
		}
		else
		{
			x = 0.0f;
			y = 0.0f;
			z = 0.0f;
		}

		w = 1.0f;
	}
	else
	{
		x = 0.0f;
		y = 0.0f;
		z = 0.0f;
		w =	1.0f;
	}
}

Drawing::Color Vector::ToColor( void )
{
	int r = MIX_CLAMP( static_cast<int>( x * 255.0f ), 0, 255 );
	int g = MIX_CLAMP( static_cast<int>( y * 255.0f ), 0, 255 );
	int b = MIX_CLAMP( static_cast<int>( z * 255.0f ), 0, 255 );
	int a = MIX_CLAMP( static_cast<int>( w * 255.0f ), 0, 255 );

	return Drawing::Color::FromArgb( a, r, g, b );
}

void Vector::FromColor( Drawing::Color col )
{
	x = MIX_CLAMP( static_cast<float>( col.R ) / 255.0f, 0.0f, 1.0f );
	y = MIX_CLAMP( static_cast<float>( col.G ) / 255.0f, 0.0f, 1.0f );
	z = MIX_CLAMP( static_cast<float>( col.B ) / 255.0f, 0.0f, 1.0f );
	w = MIX_CLAMP( static_cast<float>( col.A ) / 255.0f, 0.0f, 1.0f );
}

System::String^ Vector::ToString()
{
	return System::String::Format( L"{0},{1},{2},{3}", x, y, z, w );
}

Vector^ Vector::Parse( System::String^ str )
{
	array<wchar_t>^ tokn= { L',' };
	array<System::String^>^ strList = nullptr;
	Vector^ vec = gcnew Vector();

	strList = str->Split( tokn );

	if( strList->Length != 4 )
	{
		return vec;
	}

	try
	{
		vec->x = System::Single::Parse( strList[0] );
		vec->y = System::Single::Parse( strList[1] );
		vec->z = System::Single::Parse( strList[2] );
		vec->w = System::Single::Parse( strList[3] );
	}
	catch( System::Exception^ )
	{
		throw;
	}

	return vec;
}

}}}
