#include "Mix/Vector2.h"

namespace Mix {

Vector2::Vector2( void )
{
	x = 0.0f;
	y = 0.0f;
}

Vector2::Vector2( const Vector2& v )
{
	x = v.x;
	y = v.y;
}

Vector2::Vector2( const Point& p )
{
	x = static_cast<Float32>( p.x );
	y = static_cast<Float32>( p.y );
}

Vector2::Vector2( Float32 vx, Float32 vy )
{
	x = vx;
	y = vy;
}

Boolean Vector2::operator == ( const Vector2& v ) const
{
	if( ( MIX_FLOAT_EQUAL( x, v.x ) == False ) ||
		( MIX_FLOAT_EQUAL( y, v.y ) == False ) )
	{
		return False;
	}

	return True;
}

Boolean Vector2::operator != ( const Vector2& v ) const
{
	if( ( MIX_FLOAT_EQUAL( x, v.x ) == False ) ||
		( MIX_FLOAT_EQUAL( y, v.y ) == False ) )
	{
		return True;
	}

	return False;
}

Vector2& Vector2::operator = ( const Vector2& v )
{
	x = v.x;
	y = v.y;

	return *this;
}

Vector2& Vector2::operator = ( const Point& p )
{
	x = static_cast<Float32>( p.x );
	y = static_cast<Float32>( p.y );

	return *this;
}

Vector2& Vector2::operator += ( const Vector2& v )
{
	x += v.x;
	y += v.y;

	return *this;
}

Vector2& Vector2::operator -= ( const Vector2& v )
{
	x -= v.x;
	y -= v.y;

	return *this;
}

Vector2& Vector2::operator *= ( const Vector2& v )
{
	x *= v.x;
	y *= v.y;

	return *this;
}

Vector2& Vector2::operator /= ( const Vector2& v )
{
	x = MIX_FLOAT_DIV( x, v.x );
	y = MIX_FLOAT_DIV( y, v.y );

	return *this;
}

Vector2 Vector2::operator + ( const Vector2& v ) const
{
	Vector2 ret( *this );

	ret.x += v.x;
	ret.y += v.y;

	return ret;
}

Vector2 Vector2::operator - ( const Vector2& v ) const
{
	Vector2 ret( *this );

	ret.x -= v.x;
	ret.y -= v.y;

	return ret;
}

Vector2 Vector2::operator * ( const Vector2& v ) const
{
	Vector2 ret( *this );

	ret.x *= v.x;
	ret.y *= v.y;

	return ret;
}

Vector2 Vector2::operator / ( const Vector2& v ) const
{
	Vector2 ret( *this );

	ret.x = MIX_FLOAT_DIV( ret.x, v.x );
	ret.y = MIX_FLOAT_DIV( ret.y, v.y );

	return ret;
}

Vector2& Vector2::operator *= ( Float32 s )
{
	x *= s;
	y *= s;

	return *this;
}

Vector2& Vector2::operator /= ( Float32 s )
{
	if( MIX_FLOAT_IS_ZERO( s ) == True )
	{
		x = 0.0f;
		y = 0.0f;
	}
	else
	{
		Float32 invS = 1.0f / s;

		x *= invS;
		y *= invS;
	}

	return *this;
}

Vector2 Vector2::operator * ( Float32 s ) const
{
	Vector2 ret( *this );

	ret.x *= s;
	ret.y *= s;

	return ret;
}

Vector2 Vector2::operator / ( Float32 s ) const
{
	Vector2 ret;

	if( MIX_FLOAT_IS_ZERO( s ) == True )
	{
		ret.x = 0.0f;
		ret.y = 0.0f;
	}
	else
	{
		Float32 invS = 1.0f / s;

		ret.x = x * invS;
		ret.y = y * invS;
	}

	return ret;
}

Vector2 Vector2::operator +( void ) const
{
	return *this;
}

Vector2 Vector2::operator -( void ) const
{
	return *this * -1.0f;
}

void Vector2::Set( Float32 vx, Float32 vy )
{
	x = vx;
	y = vy;
}

Float32 Vector2::Normalize( void )
{
	Float32 length = GetLength();

	if( MIX_FLOAT_IS_ZERO( length ) == True )
	{
		x = 0.0f;
		y = 0.0f;
	}
	else
	{
		Float32 invLength = ( 1.0f / length );

		x *= invLength;
		y *= invLength;
	}

	return length;
}

Vector2 Vector2::ToNormalize( Float32* pLength ) const
{
	Vector2 ret( *this );

	ret.Normalize();

	return ret;
}

void Vector2::Saturate( void )
{
	x = MIX_FLOAT_SATURATE( x );
	y = MIX_FLOAT_SATURATE( y );
}

Vector2 Vector2::ToSaturate( void ) const
{
	Vector2 ret( *this );

	ret.Saturate();

	return ret;
}

Float32 Vector2::GetLengthSqr( void ) const
{
	return ( x * x ) + ( y * y );
}

Float32 Vector2::GetLength( void ) const
{
	return ::sqrtf( ( x * x ) + ( y * y ) );
}

Float32 Vector2::GetLengthF( void ) const
{
	return Mix::SqrtF( ( x * x ) + ( y * y ) );
}

Float32 Vector2::Dot( const Vector2& l, const Vector2& r )
{
	return ( l.x * r.x ) + ( l.y * r.y );
}

Vector2 Vector2::Rand( void )
{
	Vector2 tmp;

	tmp.x = Mix::RandF();
	tmp.y = Mix::RandF();

	return tmp;
}

Vector2 Vector2::Rand( const Vector2& p )
{
	Vector2 tmp;

	tmp.x = Mix::RandF( p.x );
	tmp.y = Mix::RandF( p.y );

	return tmp;
}

Vector2 Vector2::Rand( const Vector2& p0, const Vector2& p1 )
{
	Vector2 tmp;

	tmp.x = Mix::RandF( p0.x, p1.x );
	tmp.y = Mix::RandF( p0.y, p1.y );

	return tmp;
}

Vector2 Vector2::Min( const Vector2& p0, const Vector2& p1 )
{
	Vector2 tmp;

	tmp.x = ( p0.x > p1.x )? p1.x : p0.x;
	tmp.y = ( p0.y > p1.y )? p1.y : p0.y;

	return tmp;
}

Vector2 Vector2::Max( const Vector2& p0, const Vector2& p1 )
{
	Vector2 tmp;

	tmp.x = ( p0.x < p1.x )? p1.x : p0.x;
	tmp.y = ( p0.y < p1.y )? p1.y : p0.y;

	return tmp;
}

Vector2 Vector2::Lerp( const Vector2& ps, const Vector2& pe, Float32 t )
{
	return ( ps * ( 1.0f - t ) ) + ( pe * t );
}

Mix::Vector2 Vector2::Slerp( const Mix::Vector2& vs, const Mix::Vector2& ve, Float32 t )
{
	Mix::Vector2 s = vs.ToNormalize();
	Mix::Vector2 e = ve.ToNormalize();

	float angle = acosf( min( 1.0f, Mix::Vector2::Dot( s, e ) ) );
	float sinTh = sinf( angle );
	float invSinTh = MIX_FLOAT_RECIPROCAL( sinTh );

	float Ps = sinf( angle * ( 1.0f - t ) );
	float Pe = sinf( angle * t );

	return ( ( Ps * s + Pe * e ) * invSinTh ).ToNormalize();
}

}