
#include <math.h>
#include "Vector3.h"

template <typename T>
Vector3<T>::Vector3()
{
	x = y = z = T(0);
}

template <typename T>
Vector3<T>::Vector3(T x, T y, T z)
{
	v[0] = x; v[1] = y; v[2] = z;
}

template <typename T>
Vector3<T>::Vector3(T x, T y)
{
	v[0] = x; v[1] = y; v[2] = T(0);
}

template <typename T>
Vector3<T>::Vector3(T s)
{
	x = y = z = s;
}

template <typename T>
template <typename U>
inline Vector3<T>::Vector3(const Vector3<U>& vec)
{
	x = T(vec.x); y = T(vec.y); z = T(vec.z);
}

template <typename T>
template <typename U>
inline Vector3<T>::Vector3(const Vector2<U>& vec)
{
	x = T(vec.x); y = T(vec.y); z = T(0);
}

template <typename T>
inline float Vector3<T>::length() const
{
	return std::sqrt((x * x) + (y * y) + (z * z));
}

template <typename T>
Vector2<T> Vector3<T>::toVec2()
{
	return Vector2<T>(x, y);
}

template <typename T>
inline Vector3<T>& Vector3<T>::normalize()
{
	float il = 1.0f / length();
	x *= il; y *= il; z *= il;
	return *this;
}

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

template <typename T>
inline bool operator==(const Vector3<T>& a, const Vector3<T>& b)
{
	return a.x == b.x && a.y == b.y && a.z == b.z;
}

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

template <typename T>
inline bool operator<(const Vector3<T>& a, const Vector3<T>& b)
{
	return a.x < b.x && a.y < b.y && a.z < b.z;
}

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

template <typename T>
inline bool operator>(const Vector3<T>& a, const Vector3<T>& b)
{
	return a.x > b.x && a.y > b.y && a.z > b.z;
}

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

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

template <typename T>
inline Vector3<T> operator+(const Vector3<T>& a, const Vector3<T>& b)
{
	return Vector3<T>(a.x + b.x, a.y + b.y, a.z + b.z);
}

template <typename T>
inline Vector3<T> operator-(const Vector3<T>& a, const Vector3<T>& b)
{
	return Vector3<T>(a.x - b.x, a.y - b.y, a.z - b.z);
}

template <typename T>
inline Vector3<T> operator/(const Vector3<T>& a, const Vector3<T>& b)
{
	return Vector3<T>(a.x / b.x, a.y / b.y, a.z / b.z);
}

template <typename T>
inline Vector3<T> operator*(const Vector3<T>& a, const Vector3<T>& b)
{
	return Vector3<T>(a.x * b.x, a.y * b.y, a.z * b.z);
}

template <typename T>
inline Vector3<T>& operator+=(Vector3<T>& a, const Vector3<T>& b)
{
	a.x += b.x; a.y += b.y; a.z += b.z;
	return a;
}

template <typename T>
inline Vector3<T>& operator-=(Vector3<T>& a, const Vector3<T>& b)
{
	a.x -= b.x; a.y -= b.y; a.z -= b.z;
	return a;
}

template <typename T>
inline Vector3<T>& operator/=(Vector3<T>& a, const Vector3<T>& b)
{
	a.x /= b.x; a.y /= b.y; a.z /= b.z;
	return a;
};

template <typename T>
inline Vector3<T>& operator*=(Vector3<T>& a, const Vector3<T>& b)
{
	a.x *= b.x; a.y *= b.y; a.z *= b.z;
	return a;
}

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

template <typename T>
inline Vector3<T> operator+(const Vector3<T>& v, T s)
{
	return Vector3<T>(v.x + s, v.y + s, v.z + s);
}

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

template <typename T>
inline Vector3<T> operator-(const Vector3<T>& v, T s)
{
	return Vector3<T>(v.x - s, v.y - s, v.z - s);
}

template <typename T>
inline Vector3<T> operator-(T s, const Vector3<T>& v)
{
	return Vector3<T>(s - v.x, s - v.y, s - v.z);
}

template <typename T>
inline Vector3<T> operator/(const Vector3<T>& v, T s)
{
	return Vector3<T>(v.x / s, v.y / s, v.z / s);
}

template <typename T>
inline Vector3<T> operator/(T s, const Vector3<T>& v)
{
	return Vector3<T>(s / v.x, s / v.y, s / v.z);
}

template <typename T>
inline Vector3<T> operator*(const Vector3<T>& v, T s)
{
	return Vector3<T>(v.x * s, v.y * s, v.z * s);
}

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

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

template <typename T>
inline bool operator<(const Vector3<T>& v, T s)
{
	return v.x < s && v.y < s && v.z < s;
}

template <typename T>
inline bool operator<(T s, const Vector3<T>& v)
{
	return s < v.x && s < v.y && s < v.z;
}

template <typename T>
inline bool operator<=(const Vector3<T>& v, T s)
{
	return v.x <= s && v.y <= s && v.z <= s;
}

template <typename T>
inline bool operator<=(T s, const Vector3<T>& v)
{
	return s <= v.x && s <= v.y && s <= v.z;
}

template <typename T>
inline bool operator>(const Vector3<T>& v, T s)
{
	return v.x > s && v.y > s && v.z > s;
}

template <typename T>
inline bool operator>(T s, const Vector3<T>& v)
{
	return s > v.x && s > v.y && s > v.z;
}

template <typename T>
inline bool operator>=(const Vector3<T>& v, T s)
{
	return v.x >= s && v.y >= s && v.z >= s;
}

template <typename T>
inline bool operator>=(T s, const Vector3<T>& v)
{
	return s >= v.x && s >= v.y && s >= v.z;
}

template <typename T>
inline std::ostream& operator<<(std::ostream &s, const Vector3<T>& v)
{
	return s << "(" << v.x << "," << v.y << "," << v.z << ")";
}
