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

#pragma once

#include "glmVector2.h"
#include "glmSegment2.h"
#include "glmCircle2.h"
#include "glmLine2.h"
#include "glmDistance.h"

namespace glm
{
	class RandomNumberGenerator;

	/**
	* \brief A 2D triangle
	* 
	* \ingroup geometry2
	* \author Golaem <dev@golaem.com>
	*
	* \param float Manipulated scalar type (\ref Expression, double, float...)
	*/

	class GLM_CORE_API Triangle2
	{
	public:
		GLM_CLASS_STAT_ID(glm::MemoryStatIds::GolaemShared)

		/**
		* \brief Retrieve a triangle whose vertices are 0.0,0.0.
		*/
		static const Triangle2& getNullTriangle();

		/**
		* \name Construction/Destruction.
		*/

		//@{
		/** 
		* \brief Default constructor.
		*/
		Triangle2();

		/** 
		* \brief Constructor from the three points defining the triangle.
		*
		* \param p1 The first point.
		* \param p2 The second point.
		* \param p3 The third point.
		*/
		Triangle2(const Vector2 & p1, const Vector2 & p2, const Vector2 & p3);

		/**
		* \brief Copy constructor
		*/
		Triangle2(const Triangle2& triangle);

		/** 
		* \brief Assignment.
		*/
		Triangle2& operator= (const Triangle2& triangle);

		//@}

		/**
		* \name Vertices
		*/
		//@{
		const Vector2& getVertex(unsigned int index) const;
		Vector2& touchVertex(unsigned int index);
		const Vector2& operator[](unsigned int index) const;
		Vector2& operator[](unsigned int index);
		void setVertex(unsigned int index, const Vector2& position);
		void setVertices(const Vector2& p1, const Vector2& p2, const Vector2& p3);
		//@}

		/**
		* \name Properties
		*/
		//@{
		/**
		* \brief Compute and returns an edge of the triangle.
		* \param[in] index the index of the first vertex of the edge.
		* \param[out] p1 The first extremity of the edge.
		* \param[out] p2 The second extremity of the edge.
		*/
		void computeEdge(unsigned int index, Vector2& p1, Vector2& p2) const;

		/**
		* \brief Compute and returns an edge of the triangle.
		* \param[in] index the index of the first vertex of the edge.
		* \param[out] edge The edge.
		*/
		void computeEdge(unsigned int index, Segment2& edge) const;

		/**
		* \brief Computes the barycenter of the triangle.
		*
		* Using \p morePrecision a coordinate translation is performed prior to 
		* the computation of the real barycenter.
		*
		* \param[out] barycenter The triangle's barycenter.
		* \param[in] morePrecision If true, the barycenter calculation is more precised (default is true).
		*/
		void computeBarycenter(Vector2& barycenter, bool morePrecision = true) const;

		/** 
		* \brief Computes and returns the height associated to a given index point. 
		* \param index The index of the point (index < 3).
		* \return The desired height.
		*/
		float computeHeight(unsigned int index) const;

		/** 
		* \brief Computes and returns the surface of the triangle.
		*/
		float computeSurface() const;
		//@}

		/**
		* \name Degenerated triangles
		*/
		//@{
		/**
		* \brief Check if the triangle is reduced to a point.
		*/
		bool isPoint(float precision = GLM_NUMERICAL_PRECISION) const;
		/**
		* \brief Check if the triangle is degenerated.
		* 
		* We call degenerated the sliver triangles. A sliver triangle circumcircle area is much greater than its own (ie it is flat).
		*/
		bool isDegenerated(float precision = GLM_NUMERICAL_PRECISION) const;
		//@}

		/** 
		* \brief Computes a random position inside this triangle.
		* \param[in] rng The random number generator to use.
		* \param[out] position The generated position.
		*/
		void computeRandomPosition(RandomNumberGenerator& rng, Vector2& position) const;

		/**
		* \name Comparisons
		*/
		//@{
		bool operator==(const Triangle2& triangle) const;
		bool operator!=(const Triangle2& triangle) const;
		//@}

	protected:

		/**
		* \brief The vertices, protected to access Otherfloat data
		*/
		Vector2 _vertices[3];
	} ;
}


