#pragma once

#include "Vector.h"
#include <string>
#include <vector>

namespace Aftr
{


/// Represents a symmetric viewing frustum positioned in world space.
class AftrGeometryFrustum
{
public:
   AftrGeometryFrustum();

   AftrGeometryFrustum( float aspectRatioWidthToHeight, float verticalFOVDeg,
                        float nearPlaneDist, float farPlaneDist, const Vector& lookDirection,
                        const Vector& normalDirection, const Vector& cameraPos );

   virtual ~AftrGeometryFrustum();

   /// Tests if the in passed point resides within the frustum's volume. The in passed point
   /// must reside in the same reference frame as the cameraPos passed to this frustum's constructor.
   /// Returns true iff the point resides within the volume of the frustum; false, otherwise.
   bool isInFrustum( const Vector& point_worldSpace ) const noexcept;
   /// Returns normal for the ith plane [0,5]. These normals point out from the interior the view frustum.
   /// top, bottom, left, right, near, far corresponding to indices 0,1,2,3,4,5, respectively.
   /// These normals are defined in World Space (not object space).
   Vector getPlaneNormal( unsigned int i ) const noexcept; ///< Returns normal for the ith plane [0,5]. These normals point into the view frustum.
   /// Returns distance from origin along normal for ith plane [0,5].
   /// top, bottom, left, right, near, far corresponding to indices 0,1,2,3,4,5, respectively.
   /// These coefficients are defined in World Space (not object space).
   float getPlaneCoef( unsigned int i ) const noexcept; ///< Returns distance from origin along normal for ith plane [0,5].
   std::string toString() const;

   ///Returns the dimensions of this particular frustum based on the constructor params.
   float getNearPlaneWidth()    const noexcept { return this->nearPlaneWidth; }
   float getNearPlaneHeight()   const noexcept { return this->nearPlaneHeight; }
   float getFarPlaneWidth()     const noexcept { return this->farPlaneWidth; }
   float getFarPlaneHeight()    const noexcept { return this->farPlaneWidth; }
   float getNearPlaneDistance() const noexcept { return this->nearPlaneDistance; }
   float getFarPlaneDistance()  const noexcept { return this->farPlaneDistance; }

   //const std::vector< std::pair< Vector, Vector > >& getEdges() const { return this->edges; };

protected:

   void init( float aspectRatioWidthToHeight, float verticalFOVDeg,
           float nearPlaneDist, float farPlaneDist, const Vector& lookDirection,
           const Vector& normalDirection, const Vector& cameraPos );

   float topCoef = 0;
   float bottomCoef = 0;
   float leftCoef = 0;
   float rightCoef = 0;
   float nearCoef = 0;
   float farCoef = 0;
   Vector top;
   Vector bottom;
   Vector left;
   Vector right;
   Vector nearer;
   Vector farther;

   //std::vector< std::pair< Vector, Vector > > edges;

   float nearPlaneWidth = 0;
   float nearPlaneHeight = 0;
   float farPlaneWidth = 0;
   float farPlaneHeight = 0;
   float nearPlaneDistance = 0;
   float farPlaneDistance = 0;
};

} //namespace Aftr

