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

#pragma once

#include "glmVector3.h"
#include "glmRTTI.h"

namespace glm 
{
    /**
     * \brief Class handling a representation of a plane in a three dimensional space
     *
     * \ingroup geometry3
     * \author Golaem <dev@golaem.com>
     */

    class GLM_CORE_API Plane3
	{
	public:

		GLM_CLASS_STAT_ID( glm::MemoryStatIds::GolaemShared)

		/**
		* \name Construction/Destruction
		*/
		//@{
		/** 
		* \brief Default constructor with plane XY with Z=0 
		*/
		Plane3();

		/** 
		* \brief Compute a plane equation from 3 points 
		*/
		Plane3(const Vector3& p1, const Vector3& p2, const Vector3& p3);

		/** 
		* \brief Compute a plane equation from a normal and a point 
		*/
		Plane3(const Vector3& normal, const Vector3& point);

		/** 
		* \brief Computes a plane equation from normal and constant 
		*/
		Plane3(const Vector3& normal, float d);
		//@}

		/**
		* \name Normal
		* \brief The normal of the plane.
		*/
		//@{
		const Vector3& getNormal() const;
		void setNormal(const Vector3& normal);
		//@}

		/**
		* \name Constant
		* \brief The constant part of the plane (ie the signed distance between the origin and the plane). 
		*/
		//@{
		float getConstant() const;
		void setConstant(float constant);
		//@}

		/** 
		* \brief Returns signed distance between a point and the plane 
		*/
		float signedDistance(const Vector3& point) const;

		/** 
		* \brief Check if the given point lies in the plane.
		*/
		bool contains(const Vector3& point, float precision = GLM_NUMERICAL_PRECISION) const;

		/** 
		* \brief Returns the projection of a point on the plane 
		*/
		Vector3 project(const Vector3& point) const;
		Vector3 project(const Vector3& point, const Vector3& upVector) const; // project with a vector different than plane normal

		/** 
		* \brief Returns Z coordinate of a point, given X and Y coordinates 
		*/
		Vector3 zCoordinate(float x, float y) const;

		/** 
		* \brief Returns Z coordinate of a point, given X and Y coordinates 
		*/
		Vector3 zCoordinate(const Vector2& p) const;
		
		/** 
		* \brief Returns Y coordinate of a point, given X and Z coordinates 
		*/
		Vector3 yCoordinate(float x, float z) const;

		/** 
		* \brief Returns Y coordinate of a point, given X and Z coordinates 
		*/
		Vector3 yCoordinate(const Vector2& p) const;

		/** 
		* \brief Returns X coordinate of a point, given Y and Z coordinates 
		*/
		Vector3 xCoordinate(float y, float z) const;

		/** 
		* \brief Returns X coordinate of a point, given Y and Z coordinates 
		*/
		Vector3 xCoordinate(const Vector2& p) const;

		/**
		* \name Comparisons
		*/
		//@{
		bool operator<(const Plane3& plane) const;
		bool operator==(const Plane3& plane) const;
		bool operator!=(const Plane3& plane) const;
		//@}

	private:

		Vector3 _normal ;
		float _d ;
	} ;

	/** 
	* \brief Put readable info about a plan in a stream.
	*/

	std::ostream& operator<<(std::ostream& out, const Plane3& plane);	
}

