// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.

#ifndef tools_randd
#define tools_randd

#include "randT"
#include "rtausmed"

#include "S_STRING"
#include "scast"

namespace tools {

class irandd {
public:
  virtual ~irandd() {}
public:
  virtual void* cast(const std::string&) const = 0;
public:
  virtual double shootd() const = 0;
};

class rbinomiald : public virtual irandd, public rbinomial<rtausmed,double,unsigned int> {
  typedef rbinomial<rtausmed,double,unsigned int> parent;
public:
  TOOLS_SCLASS(tools::rbinomiald)
public:
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<rbinomiald>(this,a_class)) return p;
    return 0;
  }
  virtual double shootd() const {return shoot();}
public:
  rbinomiald(unsigned int a_n = 1,double a_p = 0.5):parent(m_flat,a_n,a_p),m_flat(){}
  virtual ~rbinomiald(){}
public:
  rbinomiald(const rbinomiald& a_from):irandd(a_from),parent(m_flat),m_flat(a_from.m_flat){}
  rbinomiald& operator=(const rbinomiald& a_from) {
    parent::operator=(a_from);
    m_flat = a_from.m_flat;
    return *this;
  }
protected:
  rtausmed m_flat;
};

class rgaussd :  public virtual irandd, public rgauss<rtausmed,double> {
  typedef rgauss<rtausmed,double> parent;
public:
  TOOLS_SCLASS(tools::rgaussd)
public:
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<rgaussd>(this,a_class)) return p;
    return 0;
  }
  virtual double shootd() const {return shoot();}
public:
  rgaussd(double a_mean = 0,double a_std_dev = 1):parent(m_flat,a_mean,a_std_dev),m_flat(){}
  virtual ~rgaussd(){}
public:
  rgaussd(const rgaussd& a_from):irandd(a_from),parent(m_flat),m_flat(a_from.m_flat){}
  rgaussd& operator=(const rgaussd& a_from) {
    parent::operator=(a_from);
    m_flat = a_from.m_flat;
    return *this;
  }
public:
  double shoot() const {return parent::shoot(::sqrt,::log);}
protected:
  rtausmed m_flat;
};

class rexpd : public virtual irandd, public rexp<rtausmed,double> {
  typedef rexp<rtausmed,double> parent;
public:
  TOOLS_SCLASS(tools::rexpd)
public:
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<rexpd>(this,a_class)) return p;
    return 0;
  }
  virtual double shootd() const {return shoot();}
public:
  rexpd(double a_rate = 1):parent(m_flat,a_rate),m_flat(){}
  virtual ~rexpd(){}
public:
  rexpd(const rexpd& a_from):irandd(a_from),parent(m_flat),m_flat(a_from.m_flat){}
  rexpd& operator=(const rexpd& a_from) {
    parent::operator=(a_from);
    m_flat = a_from.m_flat;
    return *this;
  }
public:
  double shoot() const {return parent::shoot(::log);}
protected:
  rtausmed m_flat;
};

class rdir2d : public rdir2<rtausmed,double> {
  typedef rdir2<rtausmed,double> parent;
public:
  TOOLS_SCLASS(tools::rdir2d)
public:
  rdir2d():parent(m_flat),m_flat(){}
  virtual ~rdir2d(){}
public:
  rdir2d(const rdir2d& a_from):parent(m_flat),m_flat(a_from.m_flat){}
  rdir2d& operator=(const rdir2d& a_from) {
    parent::operator=(a_from);
    m_flat = a_from.m_flat;
    return *this;
  }
protected:
  rtausmed m_flat;
};

class rdir3d : public rdir3<rtausmed,double> {
  typedef rdir3<rtausmed,double> parent;
public:
  TOOLS_SCLASS(tools::rdir3d)
public:
  rdir3d():parent(m_flat),m_flat(){}
  virtual ~rdir3d(){}
public:
  rdir3d(const rdir3d& a_from):parent(m_flat),m_flat(a_from.m_flat){}
  rdir3d& operator=(const rdir3d& a_from) {
    parent::operator=(a_from);
    m_flat = a_from.m_flat;
    return *this;
  }
public:
  void shoot(double& a_x,double& a_y,double& a_z) const {
    parent::shoot(a_x,a_y,a_z,::sqrt);
  }
protected:
  rtausmed m_flat;
};

}

#include "mathd"

namespace tools {

class rbwd : public virtual irandd, public rbw<rtausmed,double> {
  typedef rbw<rtausmed,double> parent;
public:
  TOOLS_SCLASS(tools::rbwd)
public:
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<rbwd>(this,a_class)) return p;
    return 0;
  }
  virtual double shootd() const {return shoot();}
public:
  rbwd(double a_mean = 0,double a_gamma = 1):parent(m_flat,a_mean,a_gamma),m_flat(){}
  virtual ~rbwd(){}
public:
  rbwd(const rbwd& a_from):irandd(a_from),parent(m_flat),m_flat(a_from.m_flat){}
  rbwd& operator=(const rbwd& a_from) {
    parent::operator=(a_from);
    m_flat = a_from.m_flat;
    return *this;
  }
public:
  double shoot() const {return parent::shoot(half_pi(),::tan);}
protected:
  rtausmed m_flat;
};

}

#include "typedefs"

namespace tools {

class rpoissd : public virtual irandd, public rpoiss<rtausmed,double,uint64> {
  typedef rpoiss<rtausmed,double,uint64> parent;
public:
  TOOLS_SCLASS(tools::rpoissd)
public:
  virtual void* cast(const std::string& a_class) const {
    if(void* p = cmp_cast<rpoissd>(this,a_class)) return p;
    return 0;
  }
  virtual double shootd() const {return double(shoot());}
public:
  rpoissd(double a_mean = 1):parent(m_flat,a_mean),m_flat(){}
  virtual ~rpoissd(){}
public:
  rpoissd(const rpoissd& a_from):irandd(a_from),parent(m_flat),m_flat(a_from.m_flat){}
  rpoissd& operator=(const rpoissd& a_from) {
    parent::operator=(a_from);
    m_flat = a_from.m_flat;
    return *this;
  }
public:
  uint64 shoot() const {return parent::shoot(two_pi(),::sqrt,::log,::exp,::cos);}
protected:
  rtausmed m_flat;
};

}

#endif
