//-----------------------------------------------------------------------------------------------
// AABB2.hpp
//
#pragma once
#ifndef include_AABB2
#define include_AABB2

//-----------------------------------------------------------------------------------------------
#include "Engine/Core/MathBase.hpp"
#include "Engine/Core/Vector2.hpp"


/////////////////////////////////////////////////////////////////////////////////////////////////
class AABB2
{
public:
	Vector2 mins;
	Vector2 maxs;

public:
	static const AABB2 ZERO_TO_ONE;

public:
	// Constructors
	~AABB2() {}
	AABB2() {}
	AABB2( const AABB2& copy );
	explicit AABB2( float initialX, float initialY );
	explicit AABB2( float minX, float minY, float maxX, float maxY );
	explicit AABB2( const Vector2& mins, const Vector2& maxs );
	explicit AABB2( const Vector2& center, float radiusX, float radiusY );
	explicit AABB2( const char* asText );

	// Mutators
	void SetFromText( const char* asText );
	void StretchToIncludePoint( const Vector2& point );
	void AddPadding( float xPaddingRadius, float yPaddingRadius );
	void Translate( const Vector2& translation );
	void TranslateX( float xTranslation );
	void TranslateY( float yTranslation );

	// Accessors
	bool IsPointInside( const Vector2& point ) const;
	bool DoesOverlapBox( const AABB2& box ) const;
	const Vector2 CalcSize() const;
	const Vector2 CalcCenter() const;
	const Vector2 GetPointAtNormalizedPositionWithinBox( const Vector2& normalizedPosition ) const;
	const Vector2 GetNormalizedPositionForPointWithinBox( const Vector2& point ) const;

	// Operators
	const AABB2 operator + ( const Vector2& translation ) const;
	const AABB2 operator - ( const Vector2& antiTranslation ) const;
	void operator += ( const Vector2& translation );
	void operator -= ( const Vector2& antiTranslation );
};


//-----------------------------------------------------------------------------------------------
inline AABB2::AABB2( const AABB2& copy )
	: mins( copy.mins )
	, maxs( copy.maxs )
{
}


//-----------------------------------------------------------------------------------------------
inline AABB2::AABB2( float initialX, float initialY )
	: mins( initialX, initialY )
	, maxs( initialX, initialY )
{
}


//-----------------------------------------------------------------------------------------------
inline AABB2::AABB2( float minX, float minY, float maxX, float maxY )
	: mins( minX, minY )
	, maxs( maxX, maxY )
{
}


//-----------------------------------------------------------------------------------------------
inline AABB2::AABB2( const Vector2& minimums, const Vector2& maximums )
	: mins( minimums )
	, maxs( maximums )
{
}


//-----------------------------------------------------------------------------------------------
inline AABB2::AABB2( const Vector2& center, float radiusX, float radiusY )
	: mins( center.x - radiusX, center.y - radiusY )
	, maxs( center.x + radiusX, center.y + radiusY )
{
}


//-----------------------------------------------------------------------------------------------
inline void AABB2::StretchToIncludePoint( const Vector2& point )
{
	if( point.x < mins.x )
		mins.x = point.x;
	if( point.x > maxs.x )
		maxs.x = point.x;
	if( point.y < mins.y )
		mins.y = point.y;
	if( point.y > maxs.y )
		maxs.y = point.y;
}


//-----------------------------------------------------------------------------------------------
inline void AABB2::AddPadding( float xPaddingRadius, float yPaddingRadius )
{
	mins.x -= xPaddingRadius;
	maxs.x += xPaddingRadius;
	mins.y -= yPaddingRadius;
	maxs.y += yPaddingRadius;
}


//-----------------------------------------------------------------------------------------------
inline void AABB2::Translate( const Vector2& translation )
{
	mins += translation;
	maxs += translation;
}


//-----------------------------------------------------------------------------------------------
inline void AABB2::TranslateX( float xTranslation )
{
	mins.x += xTranslation;
	maxs.x += xTranslation;
}



//-----------------------------------------------------------------------------------------------
inline void AABB2::TranslateY( float yTranslation )
{
	mins.y += yTranslation;
	maxs.y += yTranslation;
}


//-----------------------------------------------------------------------------------------------
inline bool AABB2::IsPointInside( const Vector2& point ) const
{
	return( point.x >= mins.x &&
			point.x <= maxs.x &&
			point.y >= mins.y &&
			point.y <= maxs.y );
}


//-----------------------------------------------------------------------------------------------
inline bool AABB2::DoesOverlapBox( const AABB2& box ) const
{
	return !(	box.mins.x > maxs.x ||
				box.maxs.x < mins.x ||
				box.mins.y > maxs.y ||
				box.maxs.y < mins.y );
}


//-----------------------------------------------------------------------------------------------
inline const Vector2 AABB2::CalcSize() const
{
	return Vector2( (maxs.x - mins.x), (maxs.y - mins.y) );
}


//-----------------------------------------------------------------------------------------------
inline const Vector2 AABB2::CalcCenter() const
{
	return Vector2( 0.5f * (mins.x + maxs.x), 0.5f * (mins.y + maxs.y) );
}


//-----------------------------------------------------------------------------------------------
inline const Vector2 AABB2::GetPointAtNormalizedPositionWithinBox( const Vector2& normalizedPosition ) const
{
	return Vector2(	mins.x + normalizedPosition.x * (maxs.x - mins.x),
					mins.y + normalizedPosition.y * (maxs.y - mins.y) );
}


//-----------------------------------------------------------------------------------------------
inline const Vector2 AABB2::GetNormalizedPositionForPointWithinBox( const Vector2& point ) const
{
	Vector2 normalizedPosition( 0.5f, 0.5f );
	if( maxs.x != mins.x )
		normalizedPosition.x = (point.x - mins.x) / (maxs.x - mins.x);

	if( maxs.y != mins.y )
		normalizedPosition.y = (point.y - mins.y) / (maxs.y - mins.y);

	return normalizedPosition;
}


//-----------------------------------------------------------------------------------------------
inline const AABB2 AABB2::operator + ( const Vector2& translation ) const
{
	return AABB2( mins.x + translation.x, mins.y + translation.y, maxs.x + translation.x, maxs.y + translation.y );
}


//-----------------------------------------------------------------------------------------------
inline const AABB2 AABB2::operator - ( const Vector2& antiTranslation ) const
{
	return AABB2( mins.x - antiTranslation.x, mins.y - antiTranslation.y, maxs.x - antiTranslation.x, maxs.y - antiTranslation.y );
}


//-----------------------------------------------------------------------------------------------
inline void AABB2::operator += ( const Vector2& translation )
{
	mins += translation;
	maxs += translation;
}


//-----------------------------------------------------------------------------------------------
inline void AABB2::operator -= ( const Vector2& antiTranslation )
{
	mins -= antiTranslation;
	maxs -= antiTranslation;
}


#endif // include_AABB2
