#pragma once

// Custom Classes
#include "NiPoint3.h"

/*!
  \file NiQuaternion.hpp
  \brief Defines a quaternion in space in WXYZ coordinates
 */

class NiQuaternion;
typedef NiQuaternion Quaternion;        //!< A typedef for a shorthand version of NiQuaternion

//! A class that defines a rotation in space
class NiQuaternion {
public:
	float w;            //!< The w coordinate
	float x;            //!< The x coordinate
	float y;            //!< The y coordinate
	float z;            //!< The z coordinate


	//! The initializer
	NiQuaternion(void);

	//! The initializer
	/*!
	  \param w The w coordinate
	  \param x The x coordinate
	  \param y The y coordinate
	  \param z The z coordinate
	 */
	NiQuaternion(float w, float x, float y, float z);

	//! Destructor
	~NiQuaternion(void);

	// MARK: Constants
	static const NiQuaternion IDENTITY;         //!< Quaternion(1, 0, 0, 0)

	// MARK: Setters / Getters

	//! Gets the W coordinate
	/*!
	  \return The w coordinate
	 */
	float GetW(void) const;

	//! Sets the W coordinate
	/*!
	  \param w The w coordinate
	 */
	void SetW(float w);

	//! Gets the X coordinate
	/*!
	  \return The x coordinate
	 */
	float GetX(void) const;

	//! Sets the X coordinate
	/*!
	  \param x The x coordinate
	 */
	void SetX(float x);

	//! Gets the Y coordinate
	/*!
	  \return The y coordinate
	 */
	float GetY(void) const;

	//! Sets the Y coordinate
	/*!
	  \param y The y coordinate
	 */
	void SetY(float y);

	//! Gets the Z coordinate
	/*!
	  \return The z coordinate
	 */
	float GetZ(void) const;

	//! Sets the Z coordinate
	/*!
	  \param z The z coordinate
	 */
	void SetZ(float z);


	// MARK: Member Functions

	//! Returns the forward vector from the quaternion
	/*!
	  \return The forward vector of the quaternion
	 */
	Vector3 GetForwardVector(void) const;

	//! Returns the up vector from the quaternion
	/*!
	  \return The up vector fo the quaternion
	 */
	Vector3 GetUpVector(void) const;

	//! Returns the right vector from the quaternion
	/*!
	  \return The right vector of the quaternion
	 */
	Vector3 GetRightVector(void) const;

	Vector3 GetEulerAngles() const;


	// MARK: Operators

	//! Operator to check for equality
	bool operator==(const NiQuaternion& rot) const;

	//! Operator to check for inequality
	bool operator!=(const NiQuaternion& rot) const;


	// MARK: Helper Functions

	//! Look from a specific point in space to another point in space (Y-locked)
	/*!
	  \param sourcePoint The source location
	  \param destPoint The destination location
	  \return The Quaternion with the rotation towards the destination
	 */
	static NiQuaternion LookAt(const NiPoint3& sourcePoint, const NiPoint3& destPoint);

	//! Look from a specific point in space to another point in space
	/*!
	  \param sourcePoint The source location
	  \param destPoint The destination location
	  \return The Quaternion with the rotation towards the destination
	 */
	static NiQuaternion LookAtUnlocked(const NiPoint3& sourcePoint, const NiPoint3& destPoint);

	//! Creates a Quaternion from a specific axis and angle relative to that axis
	/*!
	  \param axis The axis that is used
	  \param angle The angle relative to this axis
	  \return A quaternion created from the axis and angle
	 */
	static NiQuaternion CreateFromAxisAngle(const Vector3& axis, float angle);

	static NiQuaternion FromEulerAngles(const NiPoint3& eulerAngles);
};