#ifndef __BBOX2C_H__
#define __BBOX2C_H__

#include <math.h>
#include "PajaTypes.h"
#include "Vector2C.h"

namespace PajaTypes {


	//! Bounding box class.
	/*!
		BBox2C class implements two dimensional box used as bounding box.
		When specifying a bounding box you must be careful to construct it so that it
		is normalized. In other words, the minimum values and maximum values has to be
		correct. If the bounding box is not normalized many methods will return incorrect
		results. If a method needs the box ot be normalized it is mentioned. To normalize
		non-normalized bounding box use the normalize method.
		\sa normalize

		This class is implemented by the system.
	*/

	class BBox2C
	{
	public:
		//! Default constructor.
		BBox2C();
		
		//! Initialises the bounds of the box from specified maximum and minimum values.
		BBox2C( const Vector2C& rMin, const Vector2C& rMax );
		
		//! Copy constructor.
		BBox2C( const BBox2C& rBBox );
		
		//! Destructor.
		virtual ~BBox2C();

		//! Returns the width of the bounding box.
		/*!
			\return The returned value is absolute width, that is, even the min and max
			bounds are in wrong order width() will return correct result.			
		*/
		float32				width() const;

		//! Returns the height of the bounding box.
		/*!
			\return The returned value is absolute height, that is, even the min and max
			bounds are in wrong order height() will return correct result.			
		*/
		float32				height() const;

		//! Returns the center of the bounding box.
		/*!
			\return The center point of the bounding box. The center is calculated as: (min + max) / 2.
		*/
		Vector2C			center() const;
		
		//! Returns the size of the bounding box.
		/*!
			\return The size of the bounding box. Size is calculated as: max - min.
			You must normalize the bounding box to get correct size.
			You may normalize the box by calling the normalize() method.
		*/
		Vector2C			size() const;
		
		//! Determines wheter the specified point is inside the bounding box.
		/*! The box has to be normalized or this method may fail.
			You may normalize the box by calling the normalize() method.
			\return True if the point is inside the bounding box, else false.
		*/
		bool				contains( const Vector2C& rVec ) const;
		
		//! Determines wheter the specified bounding box is inside the bounding box.
		/*! Both boxes have to be normalized or this method may fail.
			You may normalize the box by calling the normalize() method.
			\return True if the specified bounding box is inside the bounding box, else false.
		*/
		bool				contains( const BBox2C& rBBox ) const;
		
		//! Trims the bounding box by the specified bounding box.
		/*! After trimming the bounding box will fit inside the trimming box.
			\param rBBox Reference to the trimming box.
			\return The trimmed bounding box.
		*/
		BBox2C				trim( const BBox2C& rBBox ) const;
		
		//! Normalizes the bounding box so that the minimum and maximum values are correct.
		/*!	This method is useful when dealing with bounding boxes which may be inverted.
			\return The normalized bounding box.
		*/
		BBox2C				normalize() const;
		
		//! Moves the bounding box by specified offset.
		/*!	\return The transformed bounding box.
		*/
		BBox2C				offset( const Vector2C& rOffset ) const;
		
		//! Combines two bounding boxes.
		/*!	Makes the dimension of a bounding box equal to the union of the bounding box and the other
			specified bounding box, and returns the union. The union is the smallest
			bounding box containing both bounding boxes.
			\return The combined bounding box.
		*/
		BBox2C				combine( const BBox2C& rBBox ) const;

		//! Returns either minimum or maximum of the box.
		/*!	The returns value depends on the given index: 0 for minimum, 1 for maximum.
			The box has to be normalized or this method may return incorrect values.
			You may normalize the box by calling the normalize() method.
			There are two versions of this method, this version enables to assign values using the assignment operator.
			\return If the specified index is 0 (zero) minimum is returned, else maximum is returned.
		*/
		Vector2C&			operator[]( int i );

		//! Returns either minimum or maximum of the box.
		/*!	The returns value depends on the given index: 0 for minimum, 1 for maximum.
			The box has to be normalized or this method may return incorrect values.
			You may normalize the box by calling the normalize()> method.
			There are two versions of this method, this version is for retrieving the values.
			\return If the specified index is 0 (zero) minimum is returned, else maximum is returned.
		*/
		const Vector2C&		operator[]( int i ) const;

		//! Compares two boxes and returns true if they are equal.
		/*!	Both boxes have to be normalized or this method may fail.
			You may normalize the box by calling the normalize() method.
			\return True if both bounding boxes are equal, else false.
		*/
		bool				operator==( const BBox2C& rBBox ) const;

		//! Compares two boxes and returns true if they are non-equal.
		/*!	Both boxes have to be normalized or this method may fail.
			You may normalize the box by calling the normalize() method.
			\return True if both bounding boxes are non-equal, else false.
		*/
		bool				operator!=( const BBox2C& rBBox ) const;

	private:
		Vector2C	m_rMin, m_rMax;
	};


	inline
	float32
	BBox2C::width() const
	{
		return (float32)fabs( m_rMax[0] - m_rMin[0] );
	}
	
	inline
	float32
	BBox2C::height() const
	{
		return (float32)fabs( m_rMax[1] - m_rMin[1] );
	}
	
	inline
	Vector2C
	BBox2C::center() const
	{
		return (m_rMin + m_rMax) * 0.5;
	}

	inline
	Vector2C
	BBox2C::size() const
	{
		return m_rMax - m_rMin;
	}
	
	inline
	bool
	BBox2C::contains( const Vector2C& rVec ) const
	{
		return (rVec[0] >= m_rMin[0] && rVec[0] <= m_rMax[0] && rVec[1] >= m_rMin[1] && rVec[1] <= m_rMax[1]);
	}
	
	inline
	bool
	BBox2C::contains( const BBox2C& rBBox ) const
	{
		return (contains( rBBox.m_rMin ) && contains( rBBox.m_rMax ));
	}

	inline
	Vector2C&
	BBox2C::operator[]( int i )
	{
		return (i == 0) ? m_rMin : m_rMax;
	}
	
	inline
	const Vector2C&
	BBox2C::operator[]( int i ) const
	{
		return (i == 0) ? m_rMin : m_rMax;
	}
	
	inline
	bool
	BBox2C::operator==( const BBox2C& rBBox ) const
	{
		return (m_rMin == rBBox.m_rMin && m_rMax == rBBox.m_rMax);
	}
	
	inline
	bool
	BBox2C::operator!=( const BBox2C& rBBox ) const
	{
		return (m_rMin != rBBox.m_rMin || m_rMax != rBBox.m_rMax);
	}

	inline
	BBox2C
	BBox2C::offset( const Vector2C& rOffset ) const
	{
		BBox2C	rRes( *this );

		rRes.m_rMin += rOffset;
		rRes.m_rMax += rOffset;

		return rRes;
	}



};	// PajaTypes

#endif // __BBOX2C_H__