//Jacek Matulewski, e-mail: jacek@fizyka.umk.pl

#ifndef WEKTOR_H
#define WEKTOR_H

#include <stdexcept>

template<typename T> struct TWektor
{
    public:
        //pola
		T X,Y,Z;
		
		//konstruktor
        TWektor()
        {
            this->X=0;
            this->Y=0;
            this->Z=0;
        };
        TWektor(T X,T Y,T Z)
        {
            this->X=X;
            this->Y=Y;
            this->Z=Z;			
        }

		//operatory
		TWektor& operator+=(const TWektor& w)
        {            
			X+=w.X;
            Y+=w.Y;
            Z+=w.Z;
            return *this;
        };
		TWektor operator+(const TWektor& w) const
        {
            return TWektor(*this) += w;
        };
		TWektor operator-() const
		{
			return TWektor(-X,-Y,-Z);
		}
		TWektor& operator-=(const TWektor& w)
        {
            X-=w.X;
            Y-=w.Y;
            Z-=w.Z;
            return *this;
        };
        TWektor operator-(const TWektor& w) const
        {
            return TWektor(*this) -= w;
        };
		TWektor& operator*=(const T a)
        {
            X*=a;
            Y*=a;
            Z*=a;
            return *this;
        };
        TWektor operator*(const T a) const
        {
            return TWektor(*this) *= a;
        };
		TWektor& operator/=(const T a)
        {
			if(a==0.0) throw std::invalid_argument("Dzielenie przez zero");
            X/=a;
            Y/=a;
            Z/=a;
            return *this;
        };		
		TWektor operator/(const T a) const
        {
            return TWektor(*this) /= a;
        };

		T operator*(const TWektor& w) const //iloczyn skalarny
        {
			return X*w.X+Y*w.Y+Z*w.Z;
        };
		TWektor<T> operator^(const TWektor& w) const //iloczyn wektorowy
		{
			TWektor<T> wynik;
			wynik.X=  Y*w.Z-Z*w.Y;
			wynik.Y=-(X*w.Z-Z*w.X);
			wynik.Z=  X*w.Y-Y*w.X;
			return wynik;
		}
		
		bool operator==(const TWektor& w) const
		{
			return X==w.X && Y==w.Y && Z==w.Z;
		}
		bool operator!=(const TWektor& w) const 
		{
			return !(*this == w);
		}

		//metody
		T Dlugosc() const
        {
            return sqrt(X*X+Y*Y+Z*Z);
        }
		void Normuj()
		{
			T dlugosc=Dlugosc();
			if (dlugosc!=0) *this/=dlugosc;
			else throw std::invalid_argument("Nie mozna unormowac zerowego wektora");
		}

		T* ZapiszWTablicy(T tablica[3]) const
		{
			tablica[0]=X;
			tablica[1]=Y;
			tablica[2]=Z;
			return tablica;
		}

};

template<typename T> TWektor<T> inline operator*(const T a,const TWektor<T> &w)
{
    return TWektor<T>(a*w.X,a*w.Y,a*w.Z);	
}

template<typename T> TWektor<T> IloczynWektorowy(TWektor<T> a,TWektor<T> b)
{
	return a^b;
}

typedef TWektor<double> Wektor;

const Wektor WektorZero=Wektor(0,0,0);
const Wektor WersorX=Wektor(1,0,0);
const Wektor WersorY=Wektor(0,1,0);
const Wektor WersorZ=Wektor(0,0,1);

#endif