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

#pragma once

#include "glmVector3.h"
#include "glmSegment2.h"

#include <utility>

namespace glm
{
	/**
	* \brief 3D segments.
	*
	* \ingroup geometry3
	* \author Golaem <dev@golaem.com>
	*
	* \param float Manipulated scalar type (\ref Expression, double, float...)
	*/

	class GLM_CORE_API Segment3
	{
	public:

		GLM_CLASS_STAT_ID( glm::MemoryStatIds::GolaemShared);

        Vector3 _p1 = Vector3::getNullVector();
        Vector3 _p2 = Vector3::getNullVector();

        Segment3();

        Segment3(const Vector3& p1, const Vector3& p2);

        Segment3(const Segment3& segment);

        ~Segment3();

        Segment3& operator=(const Segment3& segment);

        /**
		* \brief Project the segment along a given axis.
		*/
		Segment2 project(Axis::Value axis) const;

		/**
		* \brief Project the segment along the z axis.
		*/
		Segment2 projectZ() const;

		/**
		* Computes closest points C1 and C2 of S1(s)=P1+s*(Q1-P1) and
		* S2(t)=P2+t*(Q2-P2), returning s and t. Function result is squared
		* distance between between S1(s) and S2(t)
		*/
		static float closestPoints(Vector3& c1, Vector3& c2, float& s, float& t, const Segment3& s1, const Segment3& s2);

		/**
		* \name Accessors
		*/
		//@{
		Vector3 getCenter() const;
		//@}

		/**
		* \brief Returns true if the segment is isDegenerated() (i.e. if p1 ~= p2)
		*/
		bool isDegenerated(float precision = GLM_NUMERICAL_PRECISION) const;

		/**
		* \brief Computes and returns the vector equal to p2 - p1.
		*/
		Vector3 getVector() const;

		/**
		* \brief Computes and returns the normalized vector colinear to p2 - p1.
		*/
		Vector3 getNormalizedVector() const;

		/**
		* \brief Compute and returns the length of the segment.
		*/
		float getLength() const;

		/**
		* \brief Check if a point is contained in the segment.
		*/
		bool contains(const Vector3 & point, float precision = GLM_NUMERICAL_PRECISION) const;

		/**
		* \brief Return the segment point closest to the given point.
		*/
		Vector3 closestPoint(const Vector3 & point) const;

		/**
		* \brief Check if the point projects on the segment.
		* \param p The point to test.
		* \return True if the point project on the segment.
		*/
		bool projectsOn(const Vector3 & point) const;

		/**
		* \name GeometricTransformations
		*/
		//@{
        /**
         * \brief Translation
         *
         * \param translation Translation vector.
         * \return Le segment translaté
         */
        Segment3 operator+ (const Vector3 & translation) const;
		//@}

		// -------------------------------------------------------------------------------------------------------------------------
		/**
		* \name Comparisons
		*/
		//@{

		/**
		* \brief Equality test between two segments.
		*
		* \param Segment3 the other segment.
		* \return True if the two segments are equal.
		*/
		bool operator==(const Segment3 & Segment3) const;

		/**
		* \brief Approximate equality test between two segments.
		*
		* \param Segment3 the other segment.
		* \param precision the equality precision.
		* \return True if the two segments are approximately equal.
		*/
		bool approxEqual(const Segment3 & Segment3, float precision = GLM_NUMERICAL_PRECISION) const;

		/**
		* \brief Inferiority operator used for STL containers.
		*
		* \param Segment3 The given segment.
		* \return True if current segment is lexicographilly inferior to the given segment.
		*/
		bool operator<(const Segment3 & Segment3) const;
		//@}

		/**
		* \brief Computes the bounding box of the segment
		* \param[out] min The first point of the bounding box (the lowest)
		* \param[out] max The second point of the bounding box (the highest)
		*/
		void getBoundingBox(Vector3& min, Vector3& max) const;
	};
}

