#ifndef FS_PLANE
#define FS_PLANE

#include "FSVector.h"

class FSPlane
{
public:
     FSVector N;      // plane normal
     double  D;      // plane shift constant

     // constructors

     // Ax + By + Cz - D = 0
     FSPlane(double a = 1, double b = 0, double c = 0, double d = 0)
     {
          N = FSVector(a, b, c);
          D = d;
     }

     // instantiate a plane with normal Normal and D = d
     FSPlane(const FSVector& normal, double d = 0)
     {
          N = normal;
          D = d;
     }

     // instantiate a copy of Plane
     FSPlane(const FSPlane& plane)
     {
          N = plane.N;
          D = plane.D;
     }

     // instantiate a plane with three points
     FSPlane(const FSVector& vertexA, const FSVector& vertexB, const FSVector& vertexC)
     {
          FSVector normalA((vertexC - vertexA) | 1.0);  // unit normal of C - A
          FSVector normalB((vertexC - vertexB) | 1.0);  // unit normal of C - B

          N = (normalA ^ normalB) | 1.0;    // normalize cross product
          D = -vertexA % N;                 // calculate distance
     }

     // assignment operator
     const FSPlane& operator=(const FSPlane& plane)
     {    
          N = plane.N;
          D = plane.D;

          return *this;
     }

     // equality operator
     const bool operator==(const FSPlane& plane) const
     {    
          return N == plane.N && D == plane.D;
     }

     // inequality operator
     const bool operator!=(const FSPlane& plane) const
     {
          return !(*this == plane);
     }

     // is point on this plane?
     bool inline PointOnPlane(const FSVector& point)
     {
          return DistanceToPlane(point) == 0;
     }

     // return the distance of point to the plane
     double inline DistanceToPlane(const FSVector& point)
     {
          return N % point + D;
     }

     // return the intersection point of the ray to this plane
     FSVector inline RayIntersection(const FSVector& rayPos, const FSVector& rayDir)
     {
          const double a = N % rayDir;
          if (a == 0) 
                return rayPos;     // ray is parallel to plane
          
          return rayPos - rayDir * (DistanceToPlane(rayPos) / a);
     }
};

#endif