#ifndef FS_VECTOR
#define FS_VECTOR

#include <math.h>

/*
     VECTOR.H

     FSScalar
     FSVector class

     OpenGL Game Programming
     by Kevin Hawkins and Dave Astle

     Some operators of the FSVector class based on
     operators of the FSVector class by Bas Kuenen.
     Copyright (c) 2000 Bas Kuenen. All Rights Reserved.
     homepage: baskuenen.cfxweb.net
*/

typedef float FSScalar;

class FSVector
{
public:
     FSScalar x;
     FSScalar y;
     FSScalar z;    // x,y,z coordinates

public:
     FSVector(FSScalar a = 0, FSScalar b = 0, FSScalar c = 0) : x(a), y(b), z(c) {}
     FSVector(const FSVector &vec) : x(vec.x), y(vec.y), z(vec.z) {}

     // vector assignment
     const FSVector &operator=(const FSVector &vec)
     {
          x = vec.x;
          y = vec.y;
          z = vec.z;

          return *this;
     }

     // vecector equality
     const bool operator==(const FSVector &vec) const
     {
          return ((x == vec.x) && (y == vec.y) && (z == vec.z));
     }

     // vecector inequality
     const bool operator!=(const FSVector &vec) const
     {
          return !(*this == vec);
     }

     // vector add
     const FSVector operator+(const FSVector &vec) const
     {
          return FSVector(x + vec.x, y + vec.y, z + vec.z);
     }

     // vector add (opposite of negation)
     const FSVector operator+() const
     {    
          return FSVector(*this);
     }

     // vector increment
     const FSVector& operator+=(const FSVector& vec)
     {    x += vec.x;
          y += vec.y;
          z += vec.z;
          return *this;
     }

     // vector subtraction
     const FSVector operator-(const FSVector& vec) const
     {    
          return FSVector(x - vec.x, y - vec.y, z - vec.z);
     }
     
     // vector negation
     const FSVector operator-() const
     {    
          return FSVector(-x, -y, -z);
     }

     // vector decrement
     const FSVector &operator-=(const FSVector& vec)
     {
          x -= vec.x;
          y -= vec.y;
          z -= vec.z;

          return *this;
     }

     // scalar self-multiply
     const FSVector &operator*=(const FSScalar &s)
     {
          x *= s;
          y *= s;
          z *= s;
          
          return *this;
     }

     // scalar self-divecide
     const FSVector &operator/=(const FSScalar &s)
     {
          const float recip = 1/s; // for speed, one divecision

          x *= recip;
          y *= recip;
          z *= recip;

          return *this;
     }

     // post multiply by scalar
     const FSVector operator*(const FSScalar &s) const
     {
          return FSVector(x*s, y*s, z*s);
     }

     // pre multiply by scalar
     friend inline const FSVector operator*(const FSScalar &s, const FSVector &vec)
     {
          return vec*s;
     }

/*   friend inline const FSVector operator*(const FSVector &vec, const FSScalar &s)
     {
          return FSVector(vec.x*s, vec.y*s, vec.z*s);
     }

*/   // divecide by scalar
     const FSVector operator/(FSScalar s) const
     {
          s = 1/s;

          return FSVector(s*x, s*y, s*z);
     }

     // cross product
     const FSVector CrossProduct(const FSVector &vec) const
     {
          return FSVector(y*vec.z - z*vec.y, z*vec.x - x*vec.z, x*vec.y - y*vec.x);
     }

     // cross product
     const FSVector operator^(const FSVector &vec) const
     {
          return FSVector(y*vec.z - z*vec.y, z*vec.x - x*vec.z, x*vec.y - y*vec.x);
     }

     // dot product
     const FSScalar DotProduct(const FSVector &vec) const
     {
          return x*vec.x + y*vec.x + z*vec.z;
     }

     // dot product
     const FSScalar operator%(const FSVector &vec) const
     {
          return x*vec.x + y*vec.x + z*vec.z;
     }


     // length of vector
     const FSScalar Length() const
     {
          return (FSScalar)sqrt((double)(x*x + y*y + z*z));
     }

     // return the unit vector
     const FSVector UnitVector() const
     {
          return (*this) / Length();
     }

     // normalize this vector
     void Normalize()
     {
          (*this) /= Length();
     }

     const FSScalar operator!() const
     {
          return sqrtf(x*x + y*y + z*z);
     }

     // return vector with specified length
     const FSVector operator | (const FSScalar length) const
     {
          return *this * (length / !(*this));
     }

     // set length of vector equal to length
     const FSVector& operator |= (const float length)
     {
          return *this = *this | length;
     }

     // return angle between two vectors
     float inline Angle(const FSVector& normal)
     {
          return acosf(*this % normal);
     }

     // reflect this vector off surface with normal vector
     FSVector inline Reflection(const FSVector& normal)
     {    
          const FSVector vec(*this | 1);     // normalize this vector
          return (vec - normal * 2.0 * (vec % normal)) * !*this;
     }

};

#endif