#ifndef _VECTOR2_H
#define _VECTOR2_H

#include <cmath>
#include <iostream>

template <class T> class Vector2 {
  public:
	T x, y;

	Vector2()									: x(0),			y(0)		{}
	Vector2(T _xy)								: x(_xy),		y(_xy)		{}
	Vector2(T _x, T _y)							: x(_x),		y(_y)		{}

	inline	void		Set(T nx, T ny) { x = nx; y = ny; }

	template <class V>	inline	Vector2<T>&	operator +=(const Vector2<V>& r) { x += r.x;	y += r.y;	return *this; }
	template <class V>	inline	Vector2<T>&	operator -=(const Vector2<V>& r) { x -= r.x;	y -= r.y;	return *this; }
	template <class V>	inline	Vector2<T>&	operator *=(const Vector2<V>& r) { x *= r.x;	y *= r.y;	return *this; }

	template <class V>	inline	bool		operator < (const Vector2<V>& r)	const { return (x <  r.x) && (y <  r.y); }
	template <class V>	inline	bool		operator > (const Vector2<V>& r)	const { return (x >  r.x) && (y >  r.y); }
	template <class V>	inline	bool		operator <=(const Vector2<V>& r)	const { return (x <= r.x) && (y <= r.y); }
	template <class V>	inline	bool		operator >=(const Vector2<V>& r)	const { return (x >= r.x) && (y >= r.y); }
	template <class V>	inline	bool		operator ==(const Vector2<V>& r)	const { return (x == r.x) && (y == r.y); }
	template <class V>	inline	bool		operator !=(const Vector2<V>& r)	const { return (x != r.x) || (y != r.y); }

	template <class V>	inline	Vector2<T>	operator + (const Vector2<V>& r)	const { return Vector2<T>(x + r.x, y + r.y); }
	template <class V>	inline	Vector2<T>	operator - (const Vector2<V>& r)	const { return Vector2<T>(x - r.x, y - r.y); }
	template <class V>	inline	Vector2<T>	operator * (const Vector2<V>& r)	const { return Vector2<T>(x * r.x, y * r.y); }

	template <class V>	inline	T			operator , (const Vector2<V>& r)	const { return Dot(r); }

						// XXX: Retemplate the scalar operators.
						inline	Vector2<T>	operator + (const T r)				const { return Vector2<T>(x + r, y + r); }
						inline	Vector2<T>	operator - (const T r)				const { return Vector2<T>(x - r, y - r); }
						inline	Vector2<T>	operator * (const T r)				const { return Vector2<T>(x * r, y * r); }
						inline	Vector2<T>	operator / (const T r)				const { T t = 1 / r; return Vector2<T>(x * t, y * t); }

						inline	Vector2<T>&	operator +=(const T r)				{ x += r; y += r; return *this; }
						inline	Vector2<T>&	operator -=(const T r)				{ x -= r; y -= r; return *this; }
						inline	Vector2<T>&	operator *=(const T r)				{ x *= r; y *= r; return *this; }
						inline	Vector2<T>&	operator /=(const T r)				{ T t = 1 / r; return operator *=(r); }

	template <class V>	inline	T			Dot(const Vector2<V>& r)			const { return x*r.x + y*r.y; }

						inline	Vector2<T>	operator ~ ()						{ Clamp(); return Vector2<T>(1 - x, 1 - y); }
						inline	Vector2<T>	operator - ()						const { return Vector2<T>(-x, -y); }
						inline	T			Dot()								const { return x*x + y*y; }
						inline	T			Length()							const { return sqrt(Dot()); }
						inline	T			Inv_Length()						const { return Math::inv_sqrt(Dot()); }

	inline	Vector2<T>&	Invert() {
		x = -x;	y = -y;
		return *this;
	}

	inline void UpperClamp() {
		if (x > 1) x = 1;
		if (y > 1) y = 1;
	}

	inline void LowerClamp() {
		if (x < 0) x = 0;
		if (y < 0) y = 0;
	}

	inline void Clamp() {
		if (x > 1) {x = 1;} else if (x < 0) x = 0;
		if (y > 1) {y = 1;} else if (y < 0) y = 0;
	}

	inline T Accumulate() {
		return x = y = x + y;
	}

	Vector2<T> blend(const Vector2<T>& rhs, const Vector2<T> bf) {
		Vector2<T> ibf = Vector2<T>(1) - bf;
		return operator * (bf) + (ibf * rhs);
	};

	inline Vector2<T>	xySwap()	const { return Vector2<T>(y, x); }

	inline	T			Normalize() {
		double len = Dot();
		if (len > 0.0) {
			len = sqrt(len);
			operator *=(1.0 / len);
		}
		return len;
	}
};

template <class T>	inline Vector2<T>	operator * (const T l, const Vector2<T> r) { return r * l; }

#endif//_VECTOR2_H