#ifndef _VECTOR3D_
#define _VECTOR3D_


#include <cmath>
#include <iostream>
#include <algorithm>


template <typename t> class Vector3
{
public:
	t x, y, z;

	//Konstruktoren
	/*Vector3():
		x(0),
		y(0),
		z(0)
	{}*/

	Vector3():
		x(0),
		y(0),
		z(0)
	{}

	Vector3(t nx, t ny, t nz=0):
		x(nx),
		y(ny),
		z(nz)
	{}

	Vector3(t nv):
		x(nv),
		y(nv),
		z(nv)
	{}

	Vector3(t* Pointer):
		x(Pointer[0]),
		y(Pointer[1]),
		z(Pointer[2])
	{
	}

	/*Vector3(Vector2<t> &Vec):
		x(Vec.x),
		y(Vec.y),
		z(0)
	{}*/



	t lengthsqr() const//die länge zum quadratlf m
	{
		return (x*x+y*y+z*z);
	}

	t length() const//die länge
	{
		return std::sqrt(lengthsqr());
	}

	inline const Vector3 normalize()
	{
		t l=length();
		if(l!=0)
			return *this/=length();
		else
			return *this;
	}





	// Addition
	inline Vector3 operator+ (const Vector3 &v) const
	{
		return Vector3(x+v.x, y+v.y, z+v.z);
	}

	inline const Vector3 & operator+= (const Vector3 &v)
	{
		x+=v.x;
		y+=v.y;
		z+=v.z;
		return *this;
	}

	// Substraction
	inline Vector3 operator- (const Vector3 &v) const
	{
		return Vector3(x-v.x, y-v.y, z-v.z);
	}

	inline const Vector3 & operator-= (const Vector3 &v)
	{
		x-=v.x;
		y-=v.y;
		z-=v.z;
		return *this;
	}

	//inversion
	inline const Vector3 operator-() const
	{
		return Vector3(-x, -y, -z);
	}


	//Multiplikation
	inline Vector3 operator* (const t &s) const
	{
		return Vector3(x*s, y*s, z*s);
	}

	/*inline Vector3 operator* (const t &s, const Vector3 &v) const
	{
		return Vector3(v.x*s, v.y*s, v.z*s);
	}*/

	inline const Vector3 & operator*=(const t &s)
	{
		x*=s;
		y*=s;
		z*=s;
		return *this;
	}


	inline Vector3 operator/ (const t &s) const
	{
		return Vector3(x/s, y/s, z/s);
	}

	inline const Vector3 & operator/=(const t &s)
	{
		x/=s;
		y/=s;
		z/=s;
		return *this;
	}

	//Zuweisungsoperator
	inline const Vector3 operator=(const Vector3 &v)
	{
		x=v.x;
		y=v.y;
		z=v.z;
		return *this;
	}

	//Vergleichsoperator
	inline const bool operator== (const Vector3 &v) const
	{
		return (v.x==x && v.y==y && v.z==z);
	}





	//und ein cast
	template <typename d> Vector3<d> cast() const
	{
		return Vector3<d>((d)x, (d)y, (d)z);
	}
};

template<typename t> Vector3<t> operator*(const t& Scale, const Vector3<t>& Vec)
{
	return Vector3<t>(Vec.x*Scale, Vec.y*Scale, Vec.z*Scale);
}

template<typename t> float dot(Vector3<t> V1, Vector3<t> V2)
{
	return (V1.x*V2.x + V1.y*V2.y + V1.z*V2.z);
}

template<typename t> Vector3<t> cross(Vector3<t> V1, Vector3<t> V2)
{
	return Vector3<t>(	V1.y*V2.z - V1.z*V2.y,
						V1.z*V2.x - V1.x*V2.z,
						V1.x*V2.y - V1.y*V2.x);
}


template<typename t> std::ostream& operator<<(std::ostream &Stream, const Vector3<t> &Vector)
{
	return Stream << Vector.x << " " << Vector.y << " " << Vector.z;
}


template<typename t> std::istream& operator>>(std::istream &Stream, Vector3<t> &Vector)
{
	return Stream >> Vector.x >> Vector.y >> Vector.z;
}

//componentwise min,max functions for Vectors,
template<typename t> Vector3<t> component_min(const Vector3<t>& V1, const Vector3<t>& V2)
{
	return Vector3<t>(std::min(V1.x, V2.x), std::min(V1.y, V2.y), std::min(V1.z, V2.z));
}
template<typename t> Vector3<t> component_max(const Vector3<t>& V1, const Vector3<t>& V2)
{
	return Vector3<t>(std::max(V1.x, V2.x), std::max(V1.y, V2.y), std::max(V1.z, V2.z));
}

typedef Vector3<float> Vector3f;
typedef Vector3<double> Vector3d;
typedef Vector3<unsigned int> Vector3ui;
typedef Vector3<int> Vector3i;




#endif // _VECTOR3D_
