/// \file
/// {COMMON_HEADER}
///
/// \section DESCRIPTION
/// This header file provides may types for working with vectors.
#ifndef _VN_MATH_VECTOR_H_
#define _VN_MATH_VECTOR_H_

#include <cassert>
#include <sstream>
#include <ostream>
#include <cmath>

#include "exceptions.h"
#include "int.h"

namespace vn {
namespace math {

/// \brief Template for a Euclidean vector.
template <size_t tdim, typename T = float>
struct vec
{
	// Public Members /////////////////////////////////////////////////////////

public:

	/// \brief The vector's components.
	T c[tdim];

	// Constructors ///////////////////////////////////////////////////////////

public:

	/// \brief Creates a new vector with uninitialized components.
	vec() { }

	/// \brief Creates new vector with components initialized to val.
	///
	/// \param[in] val The initialization value.
	explicit vec(T val)
	{
		std::fill_n(c, tdim, val);
	}

	// Helper Methods /////////////////////////////////////////////////////////

public:

	/// \brief Vector with all of its components set to 0.
	///
	/// \return The 0 vector.
	static vec zero()
	{
		return vec<tdim, T>(0);
	}

	/// \brief Vector with all of its components set to 1.
	///
	/// \return The 1 vector.
	static vec one()
	{
		return vec<tdim, T>(1);
	}

	// Operator Overloads /////////////////////////////////////////////////////

public:

	/// \brief Indexing into the vector's components.
	///
	/// \param[in] index 0-based component index.
	/// \exception dimension_error The index exceeded the dimension of the vector.
	T& operator[](size_t index)
	{
		return const_cast<T&>(static_cast<const vec&>(*this)[index]);
	}

	/// \brief Indexing into the vector's components.
	///
	/// \param[in] index 0-based component index.
	/// \exception dimension_error The index exceeded the dimension of the vector.
	const T& operator[](size_t index) const
	{
		assert(index < tdim);

		return c[index];
	}

	/// \brief Negates the vector.
	///
	/// \return The negated vector.
	vec operator-() const
	{
		return neg();
	}

	/// \brief Adds a vector to this vector.
	///
	/// \param[in] rhs The right-side vector.
	/// \return The resulting vector.
	vec& operator+=(const vec& rhs)
	{
		for (size_t i = 0; i < tdim; i++)
			c[i] += rhs.c[i];

		return *this;
	}

	/// \brief Subtracts a vector from this vector.
	///
	/// \param[in] rhs The right-side vector.
	/// \return The resulting vector.
	vec& operator-=(const vec& rhs)
	{
		for (size_t i = 0; i < tdim; i++)
			c[i] -= rhs.c[i];

		return *this;
	}

	/// \brief Multiplies the vector by a scalar.
	///
	/// \param[in] rhs The scalar.
	/// \return The multiplied vector.
	vec& operator*=(const T& rhs)
	{
		for (size_t i = 0; i < tdim; i++)
			c[i] *= rhs;

		return *this;
	}

	/// \brief Divides the vector by a scalar.
	///
	/// \param[in] rhs The scalar.
	/// \return The divided vector.
	vec& operator/=(const T & rhs)
	{
		for (size_t i = 0; i < tdim; i++)
			c[i] /= rhs;

		return *this;
	}

	// Public Methods /////////////////////////////////////////////////////////

public:

	/// \brief The vector's dimension.
	///
	/// \return The vector's dimension.
	size_t dim() const { return tdim; }

	/// \brief Negates the vector.
	///
	/// \return The negated vector.
	vec neg() const
	{
		vec v;

		for (size_t i = 0; i < tdim; i++)
			v.c[i] = -c[i];

		return v;
	}

	/// \brief The vector's magnitude.
	///
	/// \return The magnitude.
	T mag() const
	{
		T sumOfSquares = 0;

		for (size_t i = 0; i < tdim; i++)
			sumOfSquares += c[i] * c[i];

		return sqrt(sumOfSquares);
	}

	/// \brief Adds a vector to this vector.
	///
	/// \param[in] toAdd The vector to add.
	/// \return The resulting vector.
	vec add(const vec& toAdd) const
	{
		vec v;

		for (size_t i = 0; i < tdim; i++)
			v.c[i] = c[i] + toAdd.c[i];

		return v;
	}

	/// \brief Subtracts a vector from this vector.
	///
	/// \param[in] to_sub The vector to subtract from this.
	/// \return The resulting vector.
	vec sub(const vec& to_sub) const
	{
		vec v;

		for (size_t i = 0; i < tdim; i++)
			v.c[i] = c[i] - to_sub.c[i];

		return v;
	}

	/// \brief Multiplies the vector by a scalar.
	///
	/// \param[in] scalar The scalar value.
	/// \return The multiplied vector.
	vec mult(const double& scalar) const
	{
		vec v;

		for (size_t i = 0; i < tdim; i++)
			v.c[i] = c[i] * scalar;

		return v;
	}

	/// \brief Divides the vector by a scalar.
	///
	/// \param[in] scalar The scalar value.
	/// \return The divided vector.
	vec div(const double& scalar) const
	{
		vec v;

		for (size_t i = 0; i < tdim; i++)
			v.c[i] = c[i] / scalar;

		return v;
	}

	/// \brief Normalizes the vector.
	///
	/// \return The normalized vector.
	vec norm() const
	{
		vec v;

		T m = mag();

		for (size_t i = 0; i < tdim; i++)
			v.c[i] = c[i] / m;

		return v;
	}

	/// \brief Computes the dot product of this and the provided vector.
	///
	/// \param[in] rhs The right-side vector.
	/// \return The computed dot product.
	T dot(const vec& rhs) const
	{
		T runningSum = 0;

		for (size_t i = 0; i < tdim; i++)
			runningSum += c[i] * rhs.c[i];

		return runningSum;
	}

};

// Specializations ////////////////////////////////////////////////////////////

#if defined(_MSC_VER)
	#pragma warning(push)
	
	// Disable warning about 'nonstandard extension used : nameless struct/union'.
	#pragma warning(disable:4201)
#endif

/// \brief Vector with 2 component specialization.
template <typename T>
struct vec<2, T>
{

	// Public Members /////////////////////////////////////////////////////////

public:

	union
	{
		struct
		{
			/// \brief X (0-component).
			T x;

			/// \brief Y (1-component).
			T y;
		};

		/// \brief The vector's components.
		T c[2];
	};

	// Constructors ///////////////////////////////////////////////////////////

public:

	/// \brief Creates a new vector with uninitialized components.
	vec() { }

	/// \brief Creates new vector with components initialized to val.
	///
	/// \param[in] val The initialization value.
	explicit vec(T val) : x(val), y(val) { }

	/// \brief Creates a new vector with its components inintialized to the
	///     provided values.
	///
	/// \param[in] x_val The x value.
	/// \param[in] y_val The y value.
	vec(T x_val, T y_val) : x(x_val), y(y_val) { }

	// Helper Methods /////////////////////////////////////////////////////////

public:

	/// \brief Vector with all of its components set to 0.
	///
	/// \return The 0 vector.
	static vec zero()
	{
		return vec<2, T>(0);
	}

	/// \brief Vector with all of its components set to 1.
	///
	/// \return The 1 vector.
	static vec one()
	{
		return vec<2, T>(1);
	}

	/// \brief Unit vector pointing in the X (0-component) direction.
	///
	/// \return The unit vector.
	static vec unitX()
	{
		return vec<2, T>(1, 0);
	}

	/// \brief Unit vector pointing in the Y (1-component) direction.
	///
	/// \return The unit vector.
	static vec unitY()
	{
		return vec<2, T>(0, 1);
	}


	// Operator Overloads /////////////////////////////////////////////////////

public:

	/// \brief Indexing into the vector's components.
	///
	/// \param[in] index 0-based component index.
	/// \exception dimension_error The index exceeded the dimension of the vector.
	T& operator[](size_t index)
	{
		return const_cast<T&>(static_cast<const vec&>(*this)[index]);
	}

	/// \brief Indexing into the vector's components.
	///
	/// \param[in] index 0-based component index.
	/// \exception dimension_error The index exceeded the dimension of the vector.
	const T& operator[](size_t index) const
	{
		assert(index < 2);

		return c[index];
	}

	/// \brief Negates the vector.
	///
	/// \return The negated vector.
	vec operator-() const
	{
		return neg();
	}

	/// \brief Adds a vector to this vector.
	///
	/// \param[in] rhs The right-side vector.
	/// \return The resulting vector.
	vec& operator+=(const vec& rhs)
	{
		x += rhs.x;
		y += rhs.y;

		return *this;
	}

	/// \brief Subtracts a vector from this vector.
	///
	/// \param[in] rhs The right-side vector.
	/// \return The resulting vector.
	vec& operator-=(const vec& rhs)
	{
		x -= rhs.x;
		y -= rhs.y;

		return *this;
	}

	/// \brief Multiplies the vector by a scalar.
	///
	/// \param[in] rhs The scalar.
	/// \return The multiplied vector.
	vec& operator*=(const T& rhs)
	{
		x *= rhs;
		y *= rhs;

		return *this;
	}

	/// \brief Divides the vector by a scalar.
	///
	/// \param[in] rhs The scalar.
	/// \return The divided vector.
	vec& operator/=(const T & rhs)
	{
		x /= rhs;
		y /= rhs;

		return *this;
	}

	// Public Methods /////////////////////////////////////////////////////////

public:

	/// \brief The vector's dimension.
	///
	/// \return The vector's dimension.
	size_t dim() const { return 2; }

	/// \brief Negates the vector.
	///
	/// \return The negated vector.
	vec neg() const
	{
		// TODO: Issue when the underlying type is an unsigned integer.
		#if defined(_MSC_VER)
			#pragma warning(push)
			#pragma warning(disable:4146)
		#endif

		return vec(-x, -y);

		#if defined (_MSC_VER)
			#pragma warning(pop)
		#endif
	}

	/// \brief The vector's magnitude.
	///
	/// \return The magnitude.
	T mag() const
	{
		// TODO: Might want this method to return a float even if the underlying
		//       data type is integer.
		#if defined(_MSC_VER)
			#pragma warning(push)
			#pragma warning(disable:4244)
		#endif

		#if (defined(_MSC_VER) && _MSC_VER <= 1600)
		// HACK: Visual Studio 2010 has trouble determining the correct 'sqrt'
		//       function for the template int32_t.
		return sqrt(static_cast<float>(x*x + y*y));
		#else
		// HACK:
		return sqrt(static_cast<float>(x*x + y*y));
		//return sqrt(x*x + y*y);
		#endif

		#if defined (_MSC_VER)
			#pragma warning(pop)
		#endif
	}

	/// \brief Adds a vector to this vector.
	///
	/// \param[in] toAdd The vector to add.
	/// \return The resulting vector.
	vec add(const vec& toAdd) const
	{
		return vec(x + toAdd.x, y + toAdd.y);
	}

	/// \brief Subtracts a vector from this vector.
	///
	/// \param[in] to_sub The vector to subtract from this.
	/// \return The resulting vector.
	vec sub(const vec& to_sub) const
	{
		return vec(x - to_sub.x, y - to_sub.y);
	}

	/// \brief Multiplies the vector by a scalar.
	///
	/// \param[in] scalar The scalar value.
	/// \return The multiplied vector.
	vec mult(const double& scalar) const
	{
		return vec(x * scalar, y * scalar);
	}

	/// \brief Divides the vector by a scalar.
	///
	/// \param[in] scalar The scalar value.
	/// \return The divided vector.
	vec div(const double& scalar) const
	{
		return vec(x / scalar, y / scalar);
	}

	/// \brief Normalizes the vector.
	///
	/// \return The normalized vector.
	vec norm() const
	{
		T m = mag();

		return vec(x / m, y / m);
	}

	/// \brief Computes the dot product of this and the provided vector.
	///
	/// \param[in] rhs The right-side vector.
	/// \return The computed dot product.
	T dot(const vec& rhs) const
	{
		return x*rhs.x + y*rhs.y;
	}

};


/// \brief Vector with 3 component specialization.
template <typename T>
struct vec<3, T>
{

	// Public Members /////////////////////////////////////////////////////////

public:

	union
	{
		struct
		{
			/// \brief X (0-component).
			T x;

			/// \brief Y (1-component).
			T y;

			/// \brief Z (2-component).
			T z;
		};

		struct
		{
			/// \brief Red (0-component).
			T r;

			/// \brief Green (1-component).
			T g;

			/// \brief Blue (2-component).
			T b;
		};

		// Union of template class with constructor not allowed until C++11.
		#if __cplusplus >= 201103L

		/// \brief XY (0,1-components).
		vec<2, T> xy;

		#endif
		
		/// \brief The vector's components.
		T c[3];
	};

	// Constructors ///////////////////////////////////////////////////////////

public:

	/// \brief Creates a new vector with uninitialized components.
	vec() { }

	/// \brief Creates new vector with components initialized to val.
	///
	/// \param[in] val The initialization value.
	explicit vec(T val) : x(val), y(val), z(val) { }

	/// \brief Creates a new vector with its components initialized to the
	///     provided values.
	///
	/// \param[in] x_val The x value.
	/// \param[in] y_val The y value.
	/// \param[in] z_val The z value.
	vec(const T& x_val, const T& y_val, const T& z_val) : x(x_val), y(y_val), z(z_val) { }

	// Helper Methods /////////////////////////////////////////////////////////

public:

	/// \brief Vector with all of its components set to 0.
	///
	/// \return The 0 vector.
	static vec zero()
	{
		return vec<3, T>(0);
	}

	/// \brief Vector with all of its components set to 1.
	///
	/// \return The 1 vector.
	static vec one()
	{
		return vec<3, T>(1);
	}

	/// \brief Unit vector pointing in the X (0-component) direction.
	///
	/// \return The unit vector.
	static vec unitX()
	{
		return vec<3, T>(1, 0, 0);
	}

	/// \brief Unit vector pointing in the Y (1-component) direction.
	///
	/// \return The unit vector.
	static vec unitY()
	{
		return vec<3, T>(0, 1, 0);
	}

	/// \brief Unit vector pointing in the Z (2-component) direction.
	///
	/// \return The unit vector.
	static vec unitZ()
	{
		return vec<3, T>(0, 0, 1);
	}

	// Operator Overloads /////////////////////////////////////////////////////

public:

	/// \brief Indexing into the vector's components.
	///
	/// \param[in] index 0-based component index.
	/// \exception dimension_error The index exceeded the dimension of the vector.
	T& operator[](size_t index)
	{
		return const_cast<T&>(static_cast<const vec&>(*this)[index]);
	}

	/// \brief Indexing into the vector's components.
	///
	/// \param[in] index 0-based component index.
	/// \exception dimension_error The index exceeded the dimension of the vector.
	const T& operator[](size_t index) const
	{
		assert(index < 3);

		return c[index];
	}

	/// \brief Negates the vector.
	///
	/// \return The negated vector.
	vec operator-() const
	{
		return neg();
	}

	/// \brief Adds a vector to this vector.
	///
	/// \param[in] rhs The right-side vector.
	/// \return The resulting vector.
	vec& operator+=(const vec& rhs)
	{
		for (size_t i = 0; i < 3; i++)
			c[i] += rhs.c[i];

		return *this;
	}

	/// \brief Subtracts a vector from this vector.
	///
	/// \param[in] rhs The right-side vector.
	/// \return The resulting vector.
	vec& operator-=(const vec& rhs)
	{
		for (size_t i = 0; i < 3; i++)
			c[i] -= rhs.c[i];

		return *this;
	}

	/// \brief Multiplies the vector by a scalar.
	///
	/// \param[in] rhs The scalar.
	/// \return The multiplied vector.
	vec& operator*=(const T& rhs)
	{
		for (size_t i = 0; i < 3; i++)
			c[i] *= rhs;

		return *this;
	}

	/// \brief Divides the vector by a scalar.
	///
	/// \param[in] rhs The scalar.
	/// \return The divided vector.
	vec& operator/=(const T & rhs)
	{
		for (size_t i = 0; i < 3; i++)
			c[i] /= rhs;

		return *this;
	}

	// Public Methods /////////////////////////////////////////////////////////

public:

	/// \brief The vector's dimension.
	///
	/// \return The vector's dimension.
	size_t dim() const { return 3; }

	/// \brief Negates the vector.
	///
	/// \return The negated vector.
	vec neg() const
	{
		// TODO: Issue when the underlying type is an unsigned integer.
		#if defined(_MSC_VER)
			#pragma warning(push)
			#pragma warning(disable:4146)
		#endif

		return vec(-x, -y, -z);

		#if defined (_MSC_VER)
			#pragma warning(pop)
		#endif
	}

	/// \brief The vector's magnitude.
	///
	/// \return The magnitude.
	T mag() const
	{
		// TODO: Might want this method to return a float even if the underlying
		//       data type is integer.
		#if defined(_MSC_VER)
			#pragma warning(push)
			#pragma warning(disable:4244)
		#endif

		#if (defined(_MSC_VER) && _MSC_VER <= 1600)
		// HACK: Visual Studio 2010 has trouble determining the correct 'sqrt'
		//       function for the template int32_t.
		return sqrt(static_cast<float>(x*x + y*y + z*z));
		#else
		// HACK:
		return sqrt(static_cast<float>(x*x + y*y + z*z));
		//return sqrt(x*x + y*y + z*z);
		#endif

		#if defined (_MSC_VER)
			#pragma warning(pop)
		#endif
	}

	/// \brief Adds a vector to this vector.
	///
	/// \param[in] toAdd The vector to add.
	/// \return The resulting vector.
	vec add(const vec& toAdd) const
	{
		return vec(x + toAdd.x, y + toAdd.y, z + toAdd.z);
	}

	/// \brief Subtracts a vector from this vector.
	///
	/// \param[in] to_sub The vector to subtract from this.
	/// \return The resulting vector.
	vec sub(const vec& to_sub) const
	{
		return vec(x - to_sub.x, y - to_sub.y, z - to_sub.z);
	}

	/// \brief Multiplies the vector by a scalar.
	///
	/// \param[in] scalar The scalar value.
	/// \return The multiplied vector.
	vec mult(const double& scalar) const
	{
		return vec(x * scalar, y * scalar, z * scalar);
	}

	/// \brief Divides the vector by a scalar.
	///
	/// \param[in] scalar The scalar value.
	/// \return The divided vector.
	vec div(const double& scalar) const
	{
		return vec(x / scalar, y / scalar, z / scalar);
	}

	/// \brief Normalizes the vector.
	///
	/// \return The normalized vector.
	vec norm() const
	{
		T m = mag();

		return vec(x / m, y / m, z / m);
	}

	/// \brief Computes the dot product of this and the provided vector.
	///
	/// \param[in] rhs The right-side vector.
	/// \return The computed dot product.
	T dot(const vec& rhs) const
	{
		return x*rhs.x + y*rhs.y + z*rhs.z;
	}

	/// \brief Computes the cross product of this and the provided vector.
	///
	/// \param[in] rhs The right-side vector.
	/// \return The computed cross product.
	/// \exception dimension_error The dimension of the vector is not 3.
	vec<3, T> cross(const vec<3, T>& rhs) const
	{
		vec<3, T> v;

		v.c[0] = c[1] * rhs.c[2] - c[2] * rhs.c[1];
		v.c[1] = c[2] * rhs.c[0] - c[0] * rhs.c[2];
		v.c[2] = c[0] * rhs.c[1] - c[1] * rhs.c[0];

		return v;
	}

};

/// \brief Vector with 4 component specialization.
template <typename T>
struct vec<4, T>
{

	// Public Members /////////////////////////////////////////////////////////

public:

	union
	{
		struct
		{
			/// \brief X (0-component).
			T x;

			/// \brief Y (1-component).
			T y;

			/// \brief Z (2-component).
			T z;

			/// \brief W (3-component).
			T w;
		};

		struct
		{
			/// \brief Red (0-component).
			T r;

			/// \brief Green (1-component).
			T g;

			/// \brief Blue (2-component).
			T b;

			/// \brief Alpha (3-component).
			T a;
		};

		// Union of template class with constructor not allowed until C++11.
		#if __cplusplus >= 201103L

		/// \brief XY (0,1-components).
		vec<2, T> xy;

		/// \brief XYZ (0,1,2-components).
		vec<3, T> xyz;

		/// \brief RGB (0,1,2-components).
		vec<3, T> rgb;

		#endif

		/// \brief The vector's components.
		T c[4];
	};

	// Constructors ///////////////////////////////////////////////////////////

public:

	/// \brief Creates a new vector with uninitialized components.
	vec() { }

	/// \brief Creates new vector with components initialized to val.
	///
	/// \param[in] val The initialization value.
	explicit vec(T val) : x(val), y(val), z(val), w(val) { }

	/// \brief Creates a new vector with its components inintialized to the
	///     provided values.
	///
	/// \param[in] x_val The x value.
	/// \param[in] y_val The y value.
	/// \param[in] z_val The z value.
	/// \param[in] w_val The w value.
	vec(T x_val, T y_val, T z_val, T w_val) : x(x_val), y(y_val), z(z_val), w(w_val) { }

	// Helper Methods /////////////////////////////////////////////////////////

public:

	/// \brief Vector with all of its components set to 0.
	///
	/// \return The 0 vector.
	static vec zero()
	{
		return vec<4, T>(0);
	}

	/// \brief Vector with all of its components set to 1.
	///
	/// \return The 1 vector.
	static vec one()
	{
		return vec<4, T>(1);
	}

	/// \brief Unit vector pointing in the X (0-component) direction.
	///
	/// \return The unit vector.
	static vec unitX()
	{
		return vec<4, T>(1, 0, 0, 0);
	}

	/// \brief Unit vector pointing in the Y (1-component) direction.
	///
	/// \return The unit vector.
	static vec unitY()
	{
		return vec<4, T>(0, 1, 0, 0);
	}

	/// \brief Unit vector pointing in the Z (2-component) direction.
	///
	/// \return The unit vector.
	static vec unitZ()
	{
		return vec<4, T>(0, 0, 1, 0);
	}

	/// \brief Unit vector pointing in the W (3-component) direction.
	///
	/// \return The unit vector.
	static vec unitW()
	{
		return vec<4, T>(0, 0, 0, 1);
	}
	// Operator Overloads /////////////////////////////////////////////////////

public:

	/// \brief Indexing into the vector's components.
	///
	/// \param[in] index 0-based component index.
	/// \exception dimension_error The index exceeded the dimension of the vector.
	T& operator[](size_t index)
	{
		return const_cast<T&>(static_cast<const vec&>(*this)[index]);
	}

	/// \brief Indexing into the vector's components.
	///
	/// \param[in] index 0-based component index.
	/// \exception dimension_error The index exceeded the dimension of the vector.
	const T& operator[](size_t index) const
	{
		assert(index < 4);

		return c[index];
	}

	/// \brief Negates the vector.
	///
	/// \return The negated vector.
	vec operator-() const
	{
		return neg();
	}

	/// \brief Adds a vector to this vector.
	///
	/// \param[in] rhs The right-side vector.
	/// \return The resulting vector.
	vec& operator+=(const vec& rhs)
	{
		x += rhs.x;
		y += rhs.y;
		z += rhs.z;
		w += rhs.w;

		return *this;
	}

	/// \brief Subtracts a vector from this vector.
	///
	/// \param[in] rhs The right-side vector.
	/// \return The resulting vector.
	vec& operator-=(const vec& rhs)
	{
		x -= rhs.x;
		y -= rhs.y;
		z -= rhs.z;
		w -= rhs.w;

		return *this;
	}

	/// \brief Multiplies the vector by a scalar.
	///
	/// \param[in] rhs The scalar.
	/// \return The multiplied vector.
	vec& operator*=(const T& rhs)
	{
		x *= rhs;
		y *= rhs;
		z *= rhs;
		w *= rhs;

		return *this;
	}

	/// \brief Divides the vector by a scalar.
	///
	/// \param[in] rhs The scalar.
	/// \return The divided vector.
	vec& operator/=(const T & rhs)
	{
		x /= rhs;
		y /= rhs;
		z /= rhs;
		w /= rhs;

		return *this;
	}

	// Public Methods /////////////////////////////////////////////////////////

public:

	/// \brief The vector's dimension.
	///
	/// \return The vector's dimension.
	size_t dim() const { return 4; }

	/// \brief Negates the vector.
	///
	/// \return The negated vector.
	vec neg() const
	{
		// TODO: Issue when the underlying type is an unsigned integer.
		#if defined(_MSC_VER)
			#pragma warning(push)
			#pragma warning(disable:4146)
		#endif

		return vec(-x, -y, -z, -w);

		#if defined (_MSC_VER)
			#pragma warning(pop)
		#endif
	}

	/// \brief The vector's magnitude.
	///
	/// \return The magnitude.
	T mag() const
	{
		// TODO: Might want this method to return a float even if the underlying
		//       data type is integer.
		#if defined(_MSC_VER)
			#pragma warning(push)
			#pragma warning(disable:4244)
		#endif

		#if (defined(_MSC_VER) && _MSC_VER <= 1600)
		// HACK: Visual Studio 2010 has trouble determining the correct 'sqrt'
		//       function for the template int32_t.
		return sqrt(static_cast<float>(x*x + y*y + z*z + w*w));
		#else
		// HACK:
		return sqrt(static_cast<float>(x*x + y*y + z*z + w*w));
		//return sqrt(x*x + y*y + z*z + w*w);
		#endif

		#if defined (_MSC_VER)
			#pragma warning(pop)
		#endif
	}

	/// \brief Adds a vector to this vector.
	///
	/// \param[in] toAdd The vector to add.
	/// \return The resulting vector.
	vec add(const vec& toAdd) const
	{
		return vec(x + toAdd.x, y + toAdd.y, z + toAdd.z, w + toAdd.w);
	}

	/// \brief Subtracts a vector from this vector.
	///
	/// \param[in] to_sub The vector to subtract from this.
	/// \return The resulting vector.
	vec sub(const vec& to_sub) const
	{
		return vec(x - to_sub.x, y - to_sub.y, z - to_sub.z, w - to_sub.w);
	}

	/// \brief Multiplies the vector by a scalar.
	///
	/// \param[in] scalar The scalar value.
	/// \return The multiplied vector.
	vec mult(const double& scalar) const
	{
		return vec(x * scalar, y * scalar, z * scalar, w * scalar);
	}

	/// \brief Divides the vector by a scalar.
	///
	/// \param[in] scalar The scalar value.
	/// \return The divided vector.
	vec div(const double& scalar) const
	{
		return vec(x / scalar, y / scalar, z / scalar, w / scalar);
	}

	/// \brief Normalizes the vector.
	///
	/// \return The normalized vector.
	vec norm() const
	{
		T m = mag();

		return vec(x / m, y / m, z / m, w / m);
	}

	/// \brief Computes the dot product of this and the provided vector.
	///
	/// \param[in] rhs The right-side vector.
	/// \return The computed dot product.
	T dot(const vec& rhs) const
	{
		return x*rhs.x + y*rhs.y + z*rhs.z + w*rhs.w;
	}
};

#if defined (_MSC_VER)
	#pragma warning(pop)
#endif

// Operator Overloads /////////////////////////////////////////////////////////

/// \brief Adds two vectors together.
///
/// \param[in] lhs The left-side vector.
/// \param[in] rhs The right-side vector.
/// \return The resulting vector.
template <size_t tdim, typename T>
vec<tdim, T> operator+(vec<tdim, T> lhs, const vec<tdim, T>& rhs)
{
	lhs += rhs;

	return lhs;
}

/// \brief Subtracts a vector from another vector.
///
/// \param[in] lhs The left-side vector.
/// \param[in] rhs The right-side vector.
/// \return The resulting vector.
template <size_t tdim, typename T>
vec<tdim, T> operator-(vec<tdim, T> lhs, const vec<tdim, T>& rhs)
{
	lhs -= rhs;

	return lhs;
}

#if defined(_MSC_VER)
	#pragma warning(push)

	// The operator* and operator/ throw a warning when a vec*f is multiplied by a double.
	#pragma warning(disable:4244)
#endif

/// \brief Multiplies a vector by a scalar.  Done both ways for python
///
/// \param[in] lhs The scalar.
/// \param[in] rhs The vector.
/// \return The result.
template <size_t tdim, typename T, typename S>
vec<tdim, T> operator*(vec<tdim, T> lhs, const S& rhs)
{
	lhs *= rhs;

	return lhs;
}

/// \brief Multiplies a vector by a scalar.  Done both ways for Python
///
/// \param[in] lhs The vector.
/// \param[in] rhs The scalar.
/// \return The result.
template <size_t tdim, typename T, typename S>
vec<tdim, T> operator*(const S& rhs, vec<tdim, T> lhs)
{
	lhs *= rhs;

	return lhs;
}

/// \brief Divides a vector by a scalar.
///
/// \param[in] lhs The vector.
/// \param[in] rhs The scalar.
/// \return The result.
template <size_t tdim, typename T, typename S>
vec<tdim, T> operator/(vec<tdim, T> lhs, const S& rhs)
{
	lhs /= rhs;

	return lhs;
}

#if defined (_MSC_VER)
	#pragma warning(pop)
#endif

// Specific Typedefs //////////////////////////////////////////////////////////

/// \brief 2-component vector using <c>float</c> as its underlying data type.
typedef vec<2> vec2;

/// \brief 3-component vector using <c>float</c> as its underlying data type.
typedef vec<3> vec3;

/// \brief 4-component vector using <c>float</c> as its underlying data type.
typedef vec<4> vec4;

/// \brief 2-component vector using <c>float</c> as its underlying data type.
typedef vec<2, float> vec2f;

/// \brief 3-component vector using <c>float</c> as its underlying data type.
typedef vec<3, float> vec3f;

/// \brief 4-component vector using <c>float</c> as its underlying data type.
typedef vec<4, float> vec4f;

/// \brief 2-component vector using <c>double</c> as its underlying data type.
typedef vec<2, double> vec2d;

/// \brief 3-component vector using <c>double</c> as its underlying data type.
typedef vec<3, double> vec3d;

/// \brief 4-component vector using <c>double</c> as its underlying data type.
typedef vec<4, double> vec4d;

/// \brief 2-component vector using <c>long double</c> as its underlying data type.
typedef vec<2, long double> vec2ld;

/// \brief 3-component vector using <c>long double</c> as its underlying data type.
typedef vec<3, long double> vec3ld;

/// \brief 4-component vector using <c>long double</c> as its underlying data type.
typedef vec<4, long double> vec4ld;

/// \brief 2-component vector using <c>int32_t</c> as its underlying data type.
typedef vec<2, int32_t> vec2i32;

/// \brief Namenclature used by OpenGL API.
typedef vec2i32 ivec2;

/// \brief 3-component vector using <c>int32_t</c> as its underlying data type.
typedef vec<3, int32_t> vec3i32;

/// \brief 4-component vector using <c>int32_t</c> as its underlying data type.
typedef vec<4, int32_t> vec4i32;

/// \brief 2-component vector using <c>uint32_t</c> as its underlying data type.
typedef vec<2, uint32_t> vec2u32;

/// \brief 3-component vector using <c>uint32_t</c> as its underlying data type.
typedef vec<3, uint32_t> vec3u32;

/// \brief 4-component vector using <c>uint32_t</c> as its underlying data type.
typedef vec<4, uint32_t> vec4u32;

// Common functions for working with vectors.

/// \brief Provides a method to generate a representable string from a provided
/// vector.
///
/// \param[in] v The vector to convert to string.
/// \return The string representation.
template <size_t tdim, typename T> std::string str(vec<tdim, T> v)
{
	std::stringstream ss;
	ss << "(";
	for (size_t i = 0; i < v.dim(); i++)
	{
		ss << v[i];

		if (i + 1 < v.dim())
			ss << "; ";
	}
	ss << ")";

	return ss.str();
}

/// \brief Overloads the ostream << operator for easy usage in displaying
/// vectors.
///
/// \param[in] out The ostream being output to.
/// \param[in] v The vector to output to ostream.
/// \return Reference to the current ostream.
template <size_t tdim, typename T> std::ostream& operator<<(std::ostream& out, vec<tdim, T> v)
{
	out << str(v);
	return out;
}

}
}

#endif
