#ifndef SM_QUATERNION

#define SM_QUATERNION

#include "SM_Vector3D.h"

struct Quaternion
{
  float w, x, y, z;

  // Constructores y Destructores
  Quaternion () {}
  Quaternion (float _w, float _x, float _y, float _z);
  Quaternion (const Quaternion& q);
  Quaternion (const float& fAngle, const Vector3D& v3dAxis);

  // Conversiones
  void FromFrame(Vector3D& v3dVPN, Vector3D& v3dUp, Vector3D& v3dRight);
  void FromRotationMatrix (const float R[3][3]);
  void ToRotationMatrix (float R[3][3]) const;
  void FromAngleAxis (const float& angle, const float& ax,
      const float& ay, const float& az);
  void ToAngleAxis (float& angle, float& ax, float& ay, float& az) const;
  void FromAngleAxis (const float& angle, const Vector3D& v3dAxis);        
  void ToAngleAxis (float& angle, Vector3D& v3dAxis) const;

  // Operaciones
  Quaternion& operator= (const Quaternion& q);
  Quaternion operator+ (const Quaternion& q) const;
  Quaternion operator- (const Quaternion& q) const;
  Quaternion operator* (const Quaternion& q) const;
  Quaternion operator* (float c) const;
  friend Quaternion operator* (float c, const Quaternion& q);
  Quaternion operator- () const;

  // Funciones

  float Dot (const Quaternion& q) const;  // Producto escalara
  float Norm () const;           // Modulo
  Quaternion Inverse () const;      // Inversa
  Quaternion UnitInverse () const;    // Inversa de quaternion unitario (conjugado)
  Quaternion Exp () const;
  Quaternion Log () const;
  int operator==(const Quaternion& q) const;
  int operator!=(const Quaternion& q) const;
  Quaternion & Normalize ();

  // Rotacion de un punto por un quaternion
  Vector3D operator* (const Vector3D& pt) const;

  // Interpolacion esferica lineal
  static Quaternion Slerp (float t, const Quaternion& p,
      const Quaternion& q);

  // Setup de interpolacion esferica cuadratica
  static void Intermediate (const Quaternion& q0, const Quaternion& q1,
      const Quaternion& q2, Quaternion& a, Quaternion& b);

  // interpolacion esferica cuadratica
  static Quaternion Squad (float t, const Quaternion& p,
      const Quaternion& a, const Quaternion& b, const Quaternion& q);


  static float Angle(Quaternion& q0, Quaternion& q1);

  static Quaternion ZERO;
  static Quaternion IDENTITY;
};

#endif
