/***************************************************************************
*                                                                          *
*  Copyright (C) Golaem S.A.  All Rights Reserved.                         *
*                                                                          *
***************************************************************************/

#pragma once

#include "glmAxisAlignedBox3.h"
#include "glmMathBase.h"
#include "glmVector3.h"
#include "glmTriangle3.h"

#include "glmPODArray.h"
#include "glmDeque.h"

namespace glm
{
	/**
	* \brief This class represent a bounding box in 3D space.
	*
	* \ingroup geometry3
	* \author Golaem <dev@golaem.com>
	*
	* \param float Manipulated scalar type (\ref Expression, double, float...)
	*/

	class GLM_CORE_API BoundingBox3 : public AxisAlignedBox3
	{
	public:

		GLM_CLASS_STAT_ID( glm::MemoryStatIds::GolaemShared);

		/**
		* \brief Default constructor.
		*/
		BoundingBox3();

		/**
		* \brief Constructor form the bounds of the bounding box.
		*/
		BoundingBox3(const Vector3 & min, const Vector3 & max);

		/**
		* \brief Copy constructor.
		*/
		BoundingBox3(const AxisAlignedBox3 & box2);

		/**
		* \brief Constructor for a list of points.
		* \param points The points as a vector.
		*/
		template< class TCollection >
		BoundingBox3(const TCollection& points);

		/**
		* \brief Destructor.
		*/
		virtual ~BoundingBox3();

		/**
		* \brief Updates the bounding box with a given point.
		*/
		void update(const Vector3 & vertex);

		/**
		* \brief Updates the bounding box with a given triangle.
		*/
		void update(const Triangle3 & triangle);

		/**
		* \brief Updates the bounding box with a given vector list.
		* \param points The points as a vector.
		*/
		void update(const glm::Array<Vector3> & points);

		/**
		* \brief Computes the union of two boxes.
		*/
		BoundingBox3 operator + (const BoundingBox3 & box2) const;

		/**
		* \brief Equality operator.
		*/
		bool operator==(const BoundingBox3 & box2) const;

		/**
		* \brief Difference operator.
		*/
		bool operator!=(const BoundingBox3 & box2) const;

		/**
		* \brief Clone the instance
		*/
		virtual Volume* clone() const;

		static bool areColliding(const BoundingBox3& box1, const BoundingBox3& box2, float precision = GLM_EPSILON);

		static float distance2(const BoundingBox3& box1, const BoundingBox3& box2);
	};

	//-----------------------------------------------------------------------------
	// points vector constructor
	//-----------------------------------------------------------------------------
	template< class TCollection>
	BoundingBox3::BoundingBox3(const TCollection& points) :AxisAlignedBox3()
	{
		if (points.size() == 0)
		{
			this->_empty = true;
		}
		else
		{
			this->_empty = false;
			this->_min = *(points.begin());
			this->_max = *(points.begin());

			for (typename TCollection::const_iterator it(points.begin()); it != points.end(); ++it)
			{
				this->_min.x = min(this->_min.x, (*it).x);
				this->_min.y = min(this->_min.y, (*it).y);
				this->_min.z = min(this->_min.z, (*it).z);
				this->_max.x = max(this->_max.x, (*it).x);
				this->_max.y = max(this->_max.y, (*it).y);
				this->_max.z = max(this->_max.z, (*it).z);
			}
		}
	}
}

