/*
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<0std::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() constreturn ((T) sqrt(x*x+y*y));}
  // norm*norm
  template<typename T> inline T punkt2d<T>::norm2() constreturn (x*x+y*y);}
  // standard-skalarprodukt
  template<typename T> inline T punkt2d<T>::skp(punkt2d<T> pt) constreturn (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>(doubleint);
  template int sgn<int>(intint);
  template punkt2d<doublefabs<double>(const punkt2d<double>&);
  template punkt2d<intfabs<int>(const punkt2d<int>&);
}