#ifndef __REAL_H
#define __REAL_H

#ifndef __STRINGS_H
#include <strings.h>
#endif

#ifdef __LONGDOUBLE__

// @doc EXTERNAL

// @class real | Classe per la gestione dei numeri reali
//
// @base public | TObject
class real : public TObject
{
  // @access Private Member

  // @cmember Numero reale
  long double _dec;

  // @access Protected Member
protected:                             
  // @cmember Duplica il numero reale (vedi classe <c TObject>)
  virtual TObject* dup() const;
  // @cmember Traduce in lettere il numero reale
  char* literals() const;
  // @cmember Inserisce i punti separatori delle migliaia e riempe i decimali
  //          alla lunghezza passata (es: 3.000,20)
  char* points(int decimals = 0) const;

  // @access Public Member
public:
  operator long double () const { return _dec; }

  // @cmember Trasforma un numero dal formato inglese (decimali con punto) in
  //          formato italiano (decimali con virgola)
  static char* eng2ita(char* s);
  // @cmember Trasforma un numero dal formato italiano (decimali con virgola) in
  //          formato inglese (decimali con punto)
  static char* ita2eng(const char* s);
  // @cmember Controlla se si tratta di un numero reale (TRUE se vero)
  static bool is_real(const char* n);
  // @cmember Controlla se si tratta di un numero naturale intero (TRUE se vero)
  static bool is_natural(const char* n);

  // @cmember Trasforma un reale in stringa
  char* string(int len = 0, int dec = UNDEFINED, char pad = ' ') const;
  // @cmember Trasforma un reale in stringa (chiama <mf real::string>), ma
  //          ritorna il formato italiano
  char* stringa(int len = 0, int dec = UNDEFINED, char pad = ' ') const;
  // @cmember Ritorna la stringa con il formato passato
  char* string(const char* picture) const;

  // @cmember Controlla se si tratta di un reale uguale 0 (TRUE se 0)
  bool is_zero() const 
  { return _dec == 0.0; }
  // @cmember Ritorna il segno del reale
  int sign() const;
  // @cmember Trasforma il reale in intero (operator int era troppo pericoloso)
  long integer() const;

  // @cmember Arrotonda al numero di decimali passati
  real& round(int prec = 0) ;
  // @cmember Tronca al numero di decimali passati (default 0)
  real& trunc(int prec = 0) ;
  // @cmember Arrotonda al numero successivo (della precisione passata)
  real& ceil(int prec = 0);
  // @cmember Assegna un reale
  real& operator = (const real& a);
  // @cmember Assegna un reale
  real& operator =(long double a);
  real& operator +=(long double a);
  // @cmember Sottrae ad un reale il valore passato (passato per indirizzo)
  real& operator -=(long double b);
  // @cmember Moltiplica un reale per il valore passato (passato per indirizzo)
  real& operator *=(long double b);
  // @cmember Divide un reale per il valore passato (passato per indirizzo)
  real& operator /=(long double b);
  // @cmember Ritorna la negazione di un reale (TRUE se 0, altrimenti FALSE)
  bool operator !() const
  { return _dec == 0.0; }
  // @cmember Ritorna il risultato della differenza tra due reali
  real operator -() const;
  
  // @cmember Costruttore
  real();
  // @cmember Costruttore
  real(const real& b);
  // @cmember Costruttore
  real(long double a);
  // @cmember Costruttore
  real(const char* s);
  // @cmember Distruttore
  virtual ~real()
  {}
};

inline long double fnc_min(long double a, long double b) { return a < b ? a : b; }
inline long double fnc_max(long double a, long double b) { return a > b ? a : b; }

long double operator%(const real& a, const real& b);
void swap(real& a, real& b) ;
long double sqrt(long double) ;
long double sqr(long double) ;
long double exp10(long double) ;
long double pow(long double, long double) ;
long double exp(long double a) ;
long double log10(long double a) ;
long double log(long double a) ;
long double sin(long double a) ;
long double cos(long double a) ;
long double tan(long double a) ;
long double abs(long double a) ;

#else

#ifndef __IOSTREAM_H
#include <iostream.h>
#endif

#ifndef GMDOTH
#include <gmsys1.h>
#include <gfd.h>
#endif

// @doc EXTERNAL

// @class real | Classe per la gestione dei numeri reali
//
// @base public | TObject
class real : public TObject
{
  // @access Private Member

  // @cmember Numero reale
  DEC _dec;

  // @access Protected Member
protected:

  // @cmember Duplica il numero reale (vedi classe <c TObject>)
  virtual TObject* dup() const;
  // @cmember Traduce in lettere il numero reale
  char* literals() const;
  // @cmember Inserisce i punti separatori delle migliaia e riempe i decimali
  //          alla lunghezza passata (es: 3.000,20)
  char* points(int decimals = 0) const;

  // @access Public Member
public:
  
  
  // @cmember Rimuove gli zeri prima della virgola, aggiustando la precisione
  void trail( );
  
  // @cmember Trasforma un numero dal formato inglese (decimali con punto) in
  //          formato italiano (decimali con virgola)
  static char* eng2ita(char* s);
  // @cmember Trasforma un numero dal formato italiano (decimali con virgola) in
  //          formato inglese (decimali con punto)
  static char* ita2eng(const char* s);
  // @cmember Controlla se si tratta di un numero reale (TRUE se vero)
  static bool is_real(const char* n);
  // @cmember Controlla se si tratta di un numero naturale intero (TRUE se vero)
  static bool is_natural(const char* n);

  // @cmember Ritorna l'indirizzo del numero reale
  DEC* ptr() const
  { return (DEC*)&_dec; }
  // @cmember Trasforma un reale in stringa
  char* string(int len = 0, int dec = UNDEFINED, char pad = ' ') const;
  // @cmember Trasforma un reale in stringa (chiama <mf real::string>), ma
  //          ritorna il formato italiano
  char* stringa(int len = 0, int dec = UNDEFINED, char pad = ' ') const;
  // @cmember Ritorna la stringa con il formato passato
  char* string(const char* picture) const;

  // @cmember Ritorna la precisione del reale (numero di decimali)
  int precision() ;
  // @cmember Controlla se si tratta di un reale uguale 0 (TRUE se 0)
  bool is_zero() const;
  // @cmember Ritorna il segno del reale
  int sign() const;
  // @cmember Trasforma il reale in intero (operator int era troppo pericoloso)
  long integer() const;

  // @cmember Arrotonda al numero di decimali passati
  real& round(int prec = 0) ;
  // @cmember Tronca al numero di decimali passati (default 0)
  real& trunc(int prec = 0) ;
  // @cmember Arrotonda al numero successivo (della precisione passata)
  real& ceil(int prec = 0);
  // @cmember Assegna un reale
  real& operator =(double a);
  // @cmember Assegna un reale (passato per indirizzo)
  real& operator =(const real& b);
  // @cmember Aggiunge ad un reale il valore passato (passato per indirizzo)
  real& operator +=(const real& b);
  // @cmember Aggiunge ad un reale il valore passato
  real& operator +=(double a);
  // @cmember Sottrae ad un reale il valore passato (passato per indirizzo)
  real& operator -=(const real& b);
  // @cmember Moltiplica un reale per il valore passato (passato per indirizzo)
  real& operator *=(const real& b);
  // @cmember Divide un reale per il valore passato (passato per indirizzo)
  real& operator /=(const real& b);
  // @cmember Ritorna la negazione di un reale (TRUE se 0, altrimenti FALSE)
  bool operator !() const
  { return is_zero(); }
  // @cmember Ritorna il risultato della differenza tra due reali
  real operator -() const;

  // @cmember Costruttore
  real();
  // @cmember Costruttore
  real(const real& b);
  // @cmember Costruttore
  real(double a);
  // @cmember Costruttore
  real(const char* s);
  // @cmember Distruttore
  virtual ~real()
  {}
};

///////////////////////////////////////////////////////////
// Math operators
///////////////////////////////////////////////////////////

ostream& operator <<(ostream& out, const real& a) ;
istream& operator >>(istream& in, real& a) ;

real operator +(const real& a, const real& b) ;
real operator +(double a, const real& b) ;
real operator +(const real& a, double b) ;
real operator -(const real& a, const real& b) ;
real operator -(double a, const real& b) ;
real operator -(const real& a, double b) ;
real operator *(const real& a, const real& b) ;
real operator *(double a, const real& b) ;
real operator *(const real& a, double b) ;
real operator /(const real& a, const real& b) ;
real operator /(double a, const real& b) ;
real operator /(const real& a, double b) ;

bool operator <(const real& a, const real& b) ;
bool operator <(double a, const real& b) ;
bool operator >(const real& a, const real& b) ;
bool operator >(double a, const real& b) ;
bool operator <=(const real& a, const real& b) ;
bool operator <=(double a, const real& b) ;
bool operator >=(const real& a, const real& b) ;
bool operator >=(double a, const real& b) ;
bool operator ==(const real& a, const real& b) ;
bool operator ==(double a, const real& b) ;
bool operator !=(const real& a, const real& b) ;
bool operator !=(double a, const real& b) ;

inline bool operator <(const real& a, double b) { return operator >(b, a); }
inline bool operator >(const real& a, double b) { return operator <(b, a); }
inline bool operator <=(const real& a, double b) { return operator >=(b, a); }
inline bool operator >=(const real& a, double b) { return operator <=(b, a); }
inline bool operator ==(const real& a, double b) { return operator ==(b, a); }
inline bool operator !=(const real& a, double b) { return operator !=(b, a); }

real operator %(const real& a, const real& b) ;
void swap(real& a, real& b) ;
const real& fnc_min(const real& a, const real& b) ;
const real& fnc_max(const real& a, const real& b) ;
real sqrt(const real& a) ;
real sqr(const real& a) ;
real exp10(const real& a) ;
real pow(const real& a, const real& b) ;
real exp(const real& a) ;
real log10(const real& a) ;
real log(const real& a) ;
real sin(const real& a) ;
real cos(const real& a) ;
real tan(const real& a) ;
real abs(const real& a) ;

#endif

// TReal implementato coi maledetti DEC

extern const real ZERO;

// @class TDistrib | Classe per dividere un real in varie sue percentuali
//                   in modo che la loro somma dia sempre il real di partenza
//
// @base public | TObject
class TDistrib : public TObject
{

  // @access Private Member

  // @cmember Totale da ripartire
  real _tot;
  // @cmember Progressivo gia' distribuito
  real _prog;
  // @cmember Pronto per essere usato (tutti gli add() fatti)
  bool _ready;
  // @cmember Percentuali da distribuire
  TArray _slices;
  // @cmember Indice delle percentuali aggiunte o estratte
  int _current;
  // @cmember Precisione
  int _decs;

  // @access Public Member
public:

  // @cmember Aggiunge una percentuale per la ripartizione
  void add(real slice);
  // @cmember Ritorna il successivo degli importi suddivisi
  real get();

  // @cmember Inizializza l'oggetto
  void init(const real& r, bool zap = FALSE);
  // @cmember Assegnamento di un importo
  void operator =(const real& r)
  { init(r); }
  // @cmember Ritorna l'ultima percentuale aggiunta
  const real& last_slice() const
  {
    CHECK(_current,"TDistrib: slices not set");
    return (const real&)_slices[_current-1];
  }

  // @cmember Costruttore
  TDistrib(const real& r,int round=UNDEFINED) : _prog(0.0),_tot(r),_ready(FALSE),_current(0),_decs(round),_slices(4)
  {}
  // @cmember Distruttore
  virtual ~TDistrib()
  {}
};

// @class TImporto | Classe per la definizione di oggetti con sezione e importo
//
// @base public | TSortable
class TImporto : public TSortable
{

  // @access Private Member

  // @cmember Sezione alla quale apprtiene l'importo
  char _sezione;
  // @cmember Valore dell'importo
  real _valore;

  // @access Protected Member
protected:
  // @cmember Permette la comparazione degli importi (0 se uguali in valore
  //          ed importo)
  virtual int compare(const TSortable& s) const;

  // @access Public Member
public:
  // @cmember Ritorna la sezione dell'importo
  char sezione() const
  { return _sezione; }
  // @cmember Ritorna il valore dell'importo
  const real& valore() const
  { return _valore; }
  // @cmember Ritorna il valore dell'importo
  real& valore()
  { return _valore; }

  // @cmember Controlla se l'importo e' 0 (in qualsiasi sezione, TRUE se 0)
  bool is_zero() const
  { return _valore.is_zero(); }

  // @cmember Assegna l'importo passato
  const TImporto& operator=(const TImporto& i)
  { return set(i.sezione(), i.valore()); }
  // @cmember Assegna l'importo da una <c TToken string> (sezione ambigua se
  //          ZERO)
  const TImporto& operator=(TToken_string& sv);
  // @cmember Aggiunge all'importo l'oggetto passato
  const TImporto& operator+=(const TImporto& i);
  // @cmember Sottrae all'importo l'oggetto passato
  const TImporto& operator-=(const TImporto& i);
  // @cmember Normalizza il segno o la sezione in base al parametro s
  const TImporto& normalize(char s = '\0');
  // @cmember Inverte la sezione dell'importo
  const TImporto& swap_section();

  // @cmember Assegna sezione ed importo all'oggetto
  const TImporto& set(char s, const real& v);
  // @cmember Setta i due elementi pos e pos+1 della <c TToken_string>
  // al valore dell'importo, lasciando bianco il dare (pos) o l'avere (pos+1)
  const TImporto& add_to(TToken_string& s, int pos) const;

  // @cmember Costruttore
  TImporto(char s = 'D', const real& v = ZERO)
  { set(s, v); }
  // @cmember Costruttore (copia l'oggetto)
  TImporto(const TImporto& i) : _sezione(i._sezione), _valore(i._valore)
  {}
};

#endif // __REAL_H
