
#ifndef SPECTRE_MATH_VECTOR3_H
#define SPECTRE_MATH_VECTOR3_H

#include "Vector2.h"
#include <iostream>

template <typename T>
struct Vector3
{
	union {
		struct { 
			T x, y, z;
		};
		T v[3];
	};

	inline Vector3();

	inline Vector3(T s);

	inline Vector3(T x, T y);

	inline Vector3(T x, T y, T z);

	template <typename U>
	inline Vector3(const Vector3<U>& vec);

	template <typename U>
	inline Vector3(const Vector2<U>& vec);

	// -----------------
	// Named operations.
	// -----------------

	inline float length() const;

	inline Vector3<T>& normalize();

	inline Vector2<T> toVec2();
};

// ---------
//  Compare
// ---------

template <typename T>
inline bool operator==(const Vector3<T>& a, const Vector3<T>& b);

template <typename T>
inline bool operator!=(const Vector3<T>& a, const Vector3<T>& b);

template <typename T>
inline bool operator<(const Vector3<T>& a, const Vector3<T>& b);

template <typename T>
inline bool operator<=(const Vector3<T>& a, const Vector3<T>& b);

template <typename T>
inline bool operator>(const Vector3<T>& a, const Vector3<T>& b);

template <typename T>
inline bool operator>=(const Vector3<T>& a, const Vector3<T>& b);

// ------------
//  Arithmetic
// ------------

template <typename T>
inline Vector3<T> operator+(const Vector3<T>& a, const Vector3<T>& b);

template <typename T>
inline Vector3<T> operator-(const Vector3<T>& a, const Vector3<T>& b);

template <typename T>
inline Vector3<T> operator/(const Vector3<T>& a, const Vector3<T>& b);

template <typename T>
inline Vector3<T> operator*(const Vector3<T>& a, const Vector3<T>& b);

template <typename T>
inline Vector3<T>& operator+=(Vector3<T>& a, const Vector3<T>& b);

template <typename T>
inline Vector3<T>& operator-=(Vector3<T>& a, const Vector3<T>& b);

template <typename T>
inline Vector3<T>& operator/=(Vector3<T>& a, const Vector3<T>& b);

template <typename T>
inline Vector3<T>& operator*=(Vector3<T>& a, const Vector3<T>& b);

// -------------------
//  Scalar Arithmetic
// -------------------

template <typename T>
inline Vector3<T> operator+(const Vector3<T>& v, T s);

template <typename T>
inline Vector3<T> operator+(T s, const Vector3<T>& v);

template <typename T>
inline Vector3<T> operator-(const Vector3<T>& v, T s);

template <typename T>
inline Vector3<T> operator-(T s, const Vector3<T>& v);

template <typename T>
inline Vector3<T> operator/(const Vector3<T>& v, T s);

template <typename T>
inline Vector3<T> operator/(T s, const Vector3<T>& v);

template <typename T>
inline Vector3<T> operator*(const Vector3<T>& v, T s);

template <typename T>
inline Vector3<T> operator*(T s, const Vector3<T>& v);

// ----------------
//  Scalar compare
// ----------------

template <typename T>
inline bool operator<(const Vector3<T>& v, T s);

template <typename T>
inline bool operator<(T s, const Vector3<T>& v);

template <typename T>
inline bool operator<=(const Vector3<T>& v, T s);

template <typename T>
inline bool operator<=(T s, const Vector3<T>& v);

template <typename T>
inline bool operator>(const Vector3<T>& v, T s);

template <typename T>
inline bool operator>(T s, const Vector3<T>& v);

template <typename T>
inline bool operator>=(const Vector3<T>& v, T s);

template <typename T>
inline bool operator>=(T s, const Vector3<T>& v);

// -------------------
//  Stream operations
// -------------------

template <typename T>
inline std::ostream& operator<<(std::ostream &s, const Vector3<T>& v);

// -----------------------------
//  Common specialization types
// -----------------------------

typedef Vector3<float>		Vector3f;
typedef Vector3<int>		Vector3i;
typedef Vector3<unsigned>	Vector3u;
typedef Vector3<unsigned char>	Vector3b;

typedef Vector3<float>		vec3f;
typedef Vector3<int>		vec3i;
typedef Vector3<unsigned>	vec3u;
typedef Vector3<unsigned char>	vec3b;

#include "Vector3.inl"

#endif /* SPECTRE_MATH_VECTOR3_H */
