#ifndef INCLUDED_MATH_VECTOR
#define INCLUDED_MATH_VECTOR

#include "Utils.h"

#include <LinearMath/btVector3.h>

#include <sstream>

//////////////////////////////////////////////////////////////
namespace Dubious {
namespace Math	{

template<int T> class VectorTemplate;
template<int T> VectorTemplate<T> operator+( const VectorTemplate<T>& A, const VectorTemplate<T>& B );
template<int T> VectorTemplate<T> operator-( const VectorTemplate<T>& A, const VectorTemplate<T>& B );
template<int T> VectorTemplate<T> operator*( const VectorTemplate<T>& A, const float& B );
template<int T> VectorTemplate<T> operator/( const VectorTemplate<T>& A, const float& B );

/// @brief Representation of a 3D Vector.
///
/// The VectorTemplate class is used to represent a vector in the DubiousEngine.
///	It is a template only so that we can use different types of vectors to represent
///	global vectors and vectors relative to a coordinate space.  This class is a 
///	wrapper around a bullet btVector3
template <int T>
class VectorTemplate
{
public:
	/// @brief Constructor 
	///
	/// Initializes to empty vector
	VectorTemplate()
		: m_Vector( 0, 0, 0 )
	{}

	/// @brief Constructor 
	///
	/// Initializes vector to specified lengths
	/// @param X - [in] x component
	/// @param Y - [in] y component
	/// @param Z - [in] z component
	VectorTemplate( float X, float Y, float Z )
		: m_Vector( X, Y, Z )
	{}

	/// @brief Constructor 
	///
	/// Initializes vector to Bullet Vector
	/// @param V - [in] Bullet vector
	VectorTemplate( const btVector3& V )
		: m_Vector( V )
	{}

	/// @brief Performs a cross product
	/// @param V - [in] the other vector
	/// @returns a new vector that is the cross product
	VectorTemplate<T>	Cross( const VectorTemplate<T>& V ) const
	{
		return VectorTemplate<T>( m_Vector.cross( V.m_Vector ) );
	}

	/// @brief Performs a dot product
	/// @param V - [in] the other vector
	/// @returns the dot product
	const float			Dot( const VectorTemplate<T>& V ) const
	{
		return m_Vector.dot( V.m_Vector );
	}

	/// @brief Returns a normalized vector
	/// @returns normalized vector
	VectorTemplate<T>	Normalized() const
	{
		return VectorTemplate<T>( m_Vector.normalized() );
	}

	/// @brief Normalizes this vector
	void				Normalize() 
	{
		m_Vector.normalize();
	}

	/// @brief Gets the length squared of the vector.  
	///
	/// This is more efficient
	///	then getting the actual length as it avoids a call to sqrt.
	/// @returns the squared length of the vector
	const float			GetLength2() const { return m_Vector.length2(); }

	/// @brief Gets the length of the vector.  
	///
	/// This is less efficient then
	///	GetLength2, which may be all that is required in many cases.
	/// @returns the length of the vector
	const float			GetLength() const { return m_Vector.length(); }

	/// @brief Sets the length of the vector
	/// @param L - [in] the new length
	void				SetLength( float L ) { m_Vector = m_Vector.normalize() * L; }

	/// @brief Accessor
	///
	/// Returns the underlying Bullet 3D vector.  You should not
	///	use this function unless you need to interact directly with Bullet
	/// @returns constant reference to member vector
	const btVector3&	Vector() const { return m_Vector; }

	/// @brief Accessor, returns the X component of the vector
	/// @returns X component of the vector
	const float         X() const { return m_Vector.x(); }

	/// @brief Accessor, returns the Y component of the vector
	/// @returns Y component of the vector
	const float         Y() const { return m_Vector.y(); }

	/// @brief Accessor, returns the Z component of the vector
	/// @returns Z component of the vector
	const float         Z() const { return m_Vector.z(); }

	/// @brief operator +=
	void operator+=( const VectorTemplate<T>& V ) {	m_Vector += V.m_Vector;	}

	/// @brief operator -=
	void operator-=( const VectorTemplate<T>& V ) {	m_Vector -= V.m_Vector;	}

	friend VectorTemplate<T> operator+ <>( const VectorTemplate<T>& A, const VectorTemplate<T>& B );
	friend VectorTemplate<T> operator- <>( const VectorTemplate<T>& A, const VectorTemplate<T>& B );
	friend VectorTemplate<T> operator* <>( const VectorTemplate<T>& A, const float& B );
	friend VectorTemplate<T> operator/ <>( const VectorTemplate<T>& A, const float& B );

private:
	btVector3			m_Vector;
};

//////////////////////////////////////////////////////////////
template<int T> 
inline bool operator==( const VectorTemplate<T>& A, const VectorTemplate<T>& B )
{
	return Equals( A.X(), B.X() ) &&
		   Equals( A.Y(), B.Y() ) &&
		   Equals( A.Z(), B.Z() );
}

//////////////////////////////////////////////////////////////
template<int T>
inline VectorTemplate<T> operator+( const VectorTemplate<T>& A, const VectorTemplate<T>& B )
{
	return A.m_Vector + B.m_Vector;
} 

//////////////////////////////////////////////////////////////
template<int T>
inline VectorTemplate<T> operator-( const VectorTemplate<T>& A, const VectorTemplate<T>& B )
{
	return A.m_Vector - B.m_Vector;
}

//////////////////////////////////////////////////////////////
template<int T>
inline VectorTemplate<T> operator*( const VectorTemplate<T>& A, const float& B )
{
	return A.m_Vector * B;
}

//////////////////////////////////////////////////////////////
template<int T>
inline VectorTemplate<T> operator/( const VectorTemplate<T>& A, const float& B )
{
	return A.m_Vector / B;
}

//////////////////////////////////////////////////////////////
template<int T>
inline std::ostream& operator<<( std::ostream& o, const VectorTemplate<T>& V )
{
	o << "(" << V.X() << ", " << V.Y() << ", " << V.Z() << ")";
	return o;
}

typedef VectorTemplate<0> Vector;
typedef VectorTemplate<1> LocalVector;
typedef VectorTemplate<2> CubeVector;
}
}

#endif
