/*
author:
	seth from http://www.bierdatenbank.de
tab size:
	2 (otherwise hardly readable!)
*/
#include <iostream>   // fuer cout, endl, max...
#include <cmath>      // fuer mathe-funktionen
#include "seth_std.h"

namespace seth_std{
	// sgn(a, sgn(0)) (vorzeichenfunktion)
	template<typename T>
	inline int sgn(T a, int zero){
		return (a>0)?1:(a==0)?zero:-1;
	}
	// x^y, x,y int, y>=0
	int pow(int basis, int exponent){
		if(exponent<0) std::cout <<"error: exponent bei int pow(int, int) muss ganzzahlig nichtnegativ sein"<<std::endl;
		int res=1;
		for(int i=0;i<exponent;++i) res*=basis;
		return res;
	}

	// mem_usage:: speichernutzungs-informationen
	int mem_usage::mem_in_use=0;     // momentan benutzter speicher
	int mem_usage::max_mem_in_use=0; // max. benutzter speicher
	// liefer max_mem_in_use
	int mem_usage::get_max_mem(){ return max_mem_in_use;}
	// speichernutzungs-informationen
	int mem_usage::mem_info(bool verbose){
		if(verbose){
			printf(" memory used: %.3fkiB\n",max_mem_in_use/1024.0);
			if(mem_in_use) printf(" memory still in use: %.3fkiB\n", mem_in_use/1024.0);
		}
		return mem_in_use;
	}
	// speicher, der benutzt wird
	int mem_usage::used_mem(int mem){
		mem_in_use+=mem;
		max_mem_in_use=std::max(max_mem_in_use, mem_in_use);
		return mem_in_use;
	}
	// speicher, der freigegeben wird
	int mem_usage::released_mem(int mem){
		mem_in_use-=mem;
		return mem_in_use;
	}

	// chronometer:: zeitmessung
	// starte uhr
	void chronometer::start_time(){
		t_start=clock();
		t_end=t_start;
	}
	// stoppe uhr
	void chronometer::stop_time(){ t_end=clock();}
	// zeit_mess_informationen
	unsigned chronometer::time_info(bool verbose){
		clock_t h;
		h=(t_start==t_end)?clock():t_end;
		unsigned time_used=(((h-t_start)*1000)/CLOCKS_PER_SEC);
		if(verbose) std::cout <<" time needed: "<<time_used<<" msec"<<std::endl;
		return time_used;
	}

	// punkt2d<T>::
	// ctor
	template<typename T> inline punkt2d<T>::punkt2d(T a, T b)
			: x (a), y (b){}
	// copy-ctor
	template<typename T> inline punkt2d<T>::punkt2d(const punkt2d<T>& src)
			: x (src.x), y (src.y){}
	// operator= punkt2d
	template<typename T> inline punkt2d<T>& punkt2d<T>::operator=(const punkt2d<T>& src){
		x=src.x;
		y=src.y;
		return *this;
	}
	// operator= skalar
	template<typename T> inline punkt2d<T>& punkt2d<T>::operator=(T skalar){
		x=skalar;
		y=skalar;
		return *this;
	}
	// -pt : unitaerer operator; negiere komponentenweise
	template<typename T> inline punkt2d<T> punkt2d<T>::operator-(){
		punkt2d<T> pt;
		pt.x=-x;
		pt.y=-y;
		return pt;
	}
	// pt+pt = pt
	template<typename T> inline punkt2d<T> punkt2d<T>::operator+(const punkt2d<T>& param) const{
		punkt2d<T> temp(*this);
		temp.x+=param.x;
		temp.y+=param.y;
		return temp;
	}
	// pt+=pt = pt
	template<typename T> inline punkt2d<T>& punkt2d<T>::operator+=(const punkt2d<T>& param){
		x+=param.x;
		y+=param.y;
		return *this;
	}
	// pt+s = pt (komponentenweise)
	template<typename T> inline punkt2d<T> punkt2d<T>::operator+(T skalar) const{
		punkt2d<T> temp(*this);
		temp.x+=skalar;
		temp.y+=skalar;
		return temp;
	}
	// pt+=s = pt
	template<typename T> inline punkt2d<T>& punkt2d<T>::operator+=(T skalar){
		x+=skalar;
		y+=skalar;
		return *this;
	}
	// pt-pt = pt
	template<typename T> inline punkt2d<T> punkt2d<T>::operator-(const punkt2d<T>& param) const{
		punkt2d<T> temp(*this);
		temp.x-=param.x;
		temp.y-=param.y;
		return temp;
	}
	// pt-=pt = pt
	template<typename T> inline punkt2d<T>& punkt2d<T>::operator-=(const punkt2d<T>& param){
		x-=param.x;
		y-=param.y;
		return *this;
	}
	// pt-s = pt (komponentenweise)
	template<typename T> inline punkt2d<T> punkt2d<T>::operator-(T skalar) const{
		punkt2d<T> temp(*this);
		temp.x-=skalar;
		temp.y-=skalar;
		return temp;
	}
	// pt-=s = pt
	template<typename T> inline punkt2d<T>& punkt2d<T>::operator-=(T skalar){
		x-=skalar;
		y-=skalar;
		return *this;
	}
	// pt*pt = pt (komponentenweise)
	template<typename T> inline punkt2d<T> punkt2d<T>::operator*(const punkt2d<T>& param) const{
		punkt2d<T> temp(*this);
		temp.x*=param.x;
		temp.y*=param.y;
		return temp;
	}
	// pt*=pt = pt
	template<typename T> inline punkt2d<T>& punkt2d<T>::operator*=(const punkt2d<T>& param){
		x*=param.x;
		y*=param.y;
		return *this;
	}
	// pt*s = pt (komponentenweise)
	template<typename T> inline punkt2d<T> punkt2d<T>::operator*(T skalar) const{
		punkt2d<T> temp(*this);
		temp.x*=skalar;
		temp.y*=skalar;
		return temp;
	}
	// pt*=s = pt
	template<typename T> inline punkt2d<T>& punkt2d<T>::operator*=(T skalar){
		x*=skalar;
		y*=skalar;
		return *this;
	}
	// pt/pt = pt (komponentenweise)
	template<typename T> inline punkt2d<T> punkt2d<T>::operator/(const punkt2d<T>& param) const{
		punkt2d<T> temp(*this);
		temp.x/=param.x;
		temp.y/=param.y;
		return temp;
	}
	// pt/=pt = pt
	template<typename T> inline punkt2d<T>& punkt2d<T>::operator/=(const punkt2d<T>& param){
		x/=param.x;
		y/=param.y;
		return *this;
	}
	// pt/s = pt (komponentenweise)
	template<typename T> inline punkt2d<T> punkt2d<T>::operator/(T skalar) const{
		punkt2d<T> temp(*this);
		temp.x/=skalar;
		temp.y/=skalar;
		return temp;
	}
	// pt/=s = pt
	template<typename T> inline punkt2d<T>& punkt2d<T>::operator/=(T skalar){
		x/=skalar;
		y/=skalar;
		return *this;
	}
	// operator==
	template<typename T> inline bool punkt2d<T>::operator==(const punkt2d<T>& param) const{
		return (x==param.x && y==param.y);
	}
	// operator!=
	template<typename T> inline bool punkt2d<T>::operator!=(const punkt2d<T>& param) const{
		return !((*this)==param);
	}
	// operator<
	template<typename T> inline bool punkt2d<T>::operator<(const punkt2d<T>& param) const{
		return (x<param.x && y<param.y);
	}
	// operator<=
	template<typename T> inline bool punkt2d<T>::operator<=(const punkt2d<T>& param) const{
		return (x<=param.x && y<=param.y);
	}
	// operator>
	template<typename T> inline bool punkt2d<T>::operator>(const punkt2d<T>& param) const{
		return (x<param.x && y<param.y);
	}
	// operator>=
	template<typename T> inline bool punkt2d<T>::operator>=(const punkt2d<T>& param) const{
		return (x>=param.x && y>=param.y);
	}
	// operator== (skalar)
	template<typename T> inline bool punkt2d<T>::operator==(T param) const{
		return (x==param && y==param);
	}
	// operator!= (skalar)
	template<typename T> inline bool punkt2d<T>::operator!=(T param) const{
		return !((*this)==param);
	}
	// operator< (skalar)
	template<typename T> inline bool punkt2d<T>::operator<(T param) const{
		return (x<param && y<param);
	}
	// operator<= (skalar)
	template<typename T> inline bool punkt2d<T>::operator<=(T param) const{
		return (x<=param && y<=param);
	}
	// operator> (skalar)
	template<typename T> inline bool punkt2d<T>::operator>(T param) const{
		return (x<param && y<param);
	}
	// operator>= (skalar)
	template<typename T> inline bool punkt2d<T>::operator>=(T param) const{
		return (x>=param && y>=param);
	}
	// abs
	template<typename T> inline punkt2d<T> punkt2d<T>::abs() const{
		punkt2d<T> abs_betrag;
		abs_betrag.x=(x<0)?-x:x;
		abs_betrag.y=(y<0)?-y:y;
		return abs_betrag;
	}
	// norm
	template<typename T> inline T punkt2d<T>::norm() const{ return ((T) sqrt(x*x+y*y));}
	// norm*norm
	template<typename T> inline T punkt2d<T>::norm2() const{ return (x*x+y*y);}
	// standard-skalarprodukt
	template<typename T> inline T punkt2d<T>::skp(punkt2d<T> pt) const{ return (x*pt.x+y*pt.y);}
	// drehe einen moore-nachbarschafts-vektor
	template<typename T> inline void punkt2d<T>::nrotate(int direction){
		T h=x;
		x=sgn(x-direction*y);
		y=direction*sgn(h+direction*y);
	}

	//fabs
	template<typename T> inline punkt2d<T> fabs(const punkt2d<T>& p){
		return p.abs();
	}
	// damit die linker-errors verschwinden
	template punkt2d<int>;
	template punkt2d<double>;
	template int sgn<double>(double, int);
	template int sgn<int>(int, int);
	template punkt2d<double> fabs<double>(const punkt2d<double>&);
	template punkt2d<int> fabs<int>(const punkt2d<int>&);
}


