#ifndef GATILOV_POINT_TEMPLATE_027811
#define GATILOV_POINT_TEMPLATE_027811

#include <math.h>
#include <stdarg.h>
#include <algorithm>

template<class T, int N> struct TPoint {
	T crd[N];

#define DEFINE_MAIN_POINT_METHODS(N) 																		\
	typedef T value_type;																					\
	static const int dimension = N;																			\
	typedef TPoint<T, N> TP;																				\
	inline TPoint() {																						\
		for (int i = 0; i<N; i++) crd[i] = 0;																\
	}																										\
	inline explicit TPoint(const T *arr) {                                                                  \
		for (int i = 0; i<N; i++) crd[i] = arr[i];                                                          \
	}                                                                                                       \
	template<class F> inline explicit TPoint(const TPoint<F, N> &other) {                                   \
		for (int i = 0; i<N; i++) crd[i] = T(other[i]);                                                     \
	}                                                                                                       \
	template<int K> inline explicit TPoint(const TPoint<T, K> &other) {                                     \
		static const int S = (K<N ? K : N);                                                                 \
		for (int i = 0; i<S; i++) crd[i] = other[i];                                                        \
		for (int i = S; i<N; i++) crd[i] = 0;                                                               \
	}                                                                                                       \
	                                                                                                        \
	inline T &operator[] (int i) { return crd[i]; }                                                         \
	inline const T &operator[] (int i) const { return crd[i]; }                                             \
																											\
	inline const TP operator- () const {																	\
		TP ret;																								\
		for (int i = 0; i<N; i++) ret[i] = -crd[i];															\
		return ret;																							\
	}																										\
	                                                                                                        \
	inline TP &operator+= (const TP &b) {                                                                   \
		for (int i = 0; i<N; i++) crd[i] += b[i];                                                           \
		return *this;                                                                                       \
	}                                                                                                       \
	inline TP &operator-= (const TP &b) {                                                                   \
		for (int i = 0; i<N; i++) crd[i] -= b[i];                                                           \
		return *this;                                                                                       \
	}                                                                                                       \
	inline TP &operator*= (const TP &b) {                                                                   \
		for (int i = 0; i<N; i++) crd[i] *= b[i];                                                           \
		return *this;                                                                                       \
	}                                                                                                       \
	inline TP &operator*= (const T &b) {                                                                    \
		for (int i = 0; i<N; i++) crd[i] *= b;                                                              \
		return *this;                                                                                       \
	}                                                                                                       \
	inline TP &operator/= (const TP &b) {                                                                   \
		for (int i = 0; i<N; i++) crd[i] /= b[i];                                                           \
		return *this;                                                                                       \
	}                                                                                                       \
	inline TP &operator/= (const T &b) {                                                                    \
		for (int i = 0; i<N; i++) crd[i] /= b;                                                              \
		return *this;                                                                                       \
	}                                                                                                       \
	                                                                                                        \
	inline const TP operator+ (const TP &b) const { return TP(*this) += b; }                                \
	inline const TP operator- (const TP &b) const { return TP(*this) -= b; }                                \
	inline const TP operator* (const TP &b) const { return TP(*this) *= b; }                                \
	inline const TP operator* (const T  &b) const { return TP(*this) *= b; }                                \
	inline const TP operator/ (const TP &b) const { return TP(*this) /= b; }                                \
	inline const TP operator/ (const T  &b) const { return TP(*this) /= b; }                                \
	                                                                                                        \
	                                                                                                        \
	inline const T operator^ (const TP &b) const {                                                          \
		T res = 0;                                                                                          \
		for (int i = 0; i<N; i++) res += crd[i] * b[i];                                                     \
		return res;                                                                                         \
	}                                                                                                       \
	                                                                                                        \
	inline bool operator< (const TP &b) const {                                                             \
		for (int i = 0; i<N; i++) if (crd[i] != b[i]) return crd[i] < b[i];                                 \
		return false;                                                                                       \
	}                                                                                                       \
	inline bool operator== (const TP &b) const {                                                            \
		for (int i = 0; i<N; i++) if (crd[i] != b[i]) return false;                                         \
		return true;																						\
	}

	DEFINE_MAIN_POINT_METHODS(N)

	inline TPoint(T first, ...) {
		crd[0] = first;
		va_list vars;
		va_start(vars, first);
		for (int i = 1; i<N; i++) crd[i] = va_arg(vars, T);
		va_end(vars);
	}
};

//point1d
template<class T> struct TPoint<T, 1> {
	union {
		T crd[1];
		T x;
	};
	DEFINE_MAIN_POINT_METHODS(1)
	inline TPoint(const T &_x) : x(_x) {}
};

//point2d
template<class T> struct TPoint<T, 2> {
	union {
		T crd[2];
		struct { T x; T y; };
	};
	DEFINE_MAIN_POINT_METHODS(2)
	inline TPoint(const T &_x, const T &_y) : x(_x), y(_y) {}

	inline const T operator% (const TP &b) const {		//cross product as signed square
		return x*b.y - y*b.x;
	}
};

//point3d
template<class T> struct TPoint<T, 3> {
	union {
		T crd[3];
		struct { T x; T y; T z; };
	};
	DEFINE_MAIN_POINT_METHODS(3)
	inline TPoint(const T &_x, const T &_y, const T &_z) : x(_x), y(_y), z(_z) {}

	inline const TP operator% (const TP &b) const {		//cross product as directed square
		typedef TPoint<T, 2> TP2;
		return TP(TP2(y, z) % TP2(b.y, b.z)
				, TP2(z, x) % TP2(b.z, b.x)
				, TP2(x, y) % TP2(b.x, b.y));
	}
};

//point4d
template<class T> struct TPoint<T, 4> {
	union {
		T crd[4];
		struct { T x; T y; T z; T w; };
	};
	DEFINE_MAIN_POINT_METHODS(4)
	inline TPoint(const T &_x, const T &_y, const T &_z, const T &_w) : x(_x), y(_y), z(_z), w(_w) {}
	inline TPoint(const TPoint<T, 3> &_v, const T &_w) : x(_v.x), y(_v.y), z(_v.z), w(_w) {}		//quaternion constructor

	inline const TP operator% (const TP &b) const {		//quaternion product
		typedef TPoint<T, 3> TP3;
		const TP3 v = TP3(x, y, z);
		const TP3 bv = TP3(b.x, b.y, b.z);
		return TP(v*b.w + bv*w + (v%bv), w*b.w - (v^bv));
	}
};

//real-specific functions
template<int N> inline const double operator! (const TPoint<double, N> &p) {
	return sqrt(p ^ p);
}
template<int N> inline const float operator! (const TPoint<float, N> &p) {
	return sqrtf(p ^ p);
}

//min/max for bounding box
namespace std {
	template<class T, int N> inline const TPoint<T, N> min(const TPoint<T, N> &a, const TPoint<T, N> &b) {
		TPoint<T, N> res;
		for (int i = 0; i<N; i++) res[i] = std::min(a[i], b[i]);
		return res;
	}
	template<class T, int N> inline const TPoint<T, N> max(const TPoint<T, N> &a, const TPoint<T, N> &b) {
		TPoint<T, N> res;
		for (int i = 0; i<N; i++) res[i] = std::max(a[i], b[i]);
		return res;
	}
};

//added typedefs for our game problem
typedef TPoint<double, 2> double2;
typedef TPoint<int, 2> int2;

#endif
