#ifndef __DATE_H
#define __DATE_H

#ifndef __OBJECT_H
#include "object.h"
#endif

#define NULLDATE 0L
#define TODAY  -1L

// @doc EXTERNAL

// @enum TDate_order | Criterio col quale ordinare gli elementi della data
enum TDate_order   {
  gma_date = 1,  // @emem Giorno-Mese-Anno (default 1)
  mga_date,      // @emem Mese-Giorno-Anno
  amg_date,      // @emem Anno-Mese-Giorno
  a_date,        // @emem Solo anno
  m_date,        // @emem Solo Mese
  g_date,        // @emem Solo Giorno
  ma_date };     // @emem Mese-Anno

// @doc EXTERNAL

// @enum TDate_mgafmt | Criterio col quale visualizzare le date
enum TDate_mgafmt  {
  ANSI = -1,     // @emem Formato ANSI
  brief = 2,     // @emem Formato breve
  full = 4,      // @emem Formato completo
  letters = 5,   // @emem Lettere
  weekday = 6,   // @emem Giorno della settimana
  quarter = 7,   // @emem Formato trimestrale
  def = 99 };    // @emem Formato standard

// @doc EXTERNAL

// @class TDate | Classe per la gestione delle date
//
// @base public | TObject
class TDate : public TObject

// @author:(INTERNAL) Guido

// @access:(INTERNAL) Private Member
{

  // @cmember:(INTERNAL) Valore data in formato ANSI
  long _val;

  // @access Protected Member
protected:

  // @cmember Controlla se una data e' minore di un'altra
  friend bool operator <(const TDate& a, const TDate& b);
  // @cmember Controlla se una data e' maggiore di un'altra
  friend bool operator >(const TDate& a, const TDate& b);
  // @cmember Controlla se una data e' minore o ugaule ad un'altra
  friend bool operator <=(const TDate& a, const TDate& b);
  // @cmember Controlla se una data e' maggiore o uguale ad un'altra
  friend bool operator >=(const TDate& a, const TDate& b);
  // @cmember Controlla se 2 date sono uguali
  friend bool operator ==(const TDate& a, const TDate& b);
  // @cmember Controlla se una 2 date sono diverse
  friend bool operator !=(const TDate& a, const TDate& b);
  // @cmember Costruisce la data in formato packed
  long makedata(int day, int month, int year) const
  { return (10000L * year) + ( 100L * month) + day; }
  
  // @access Public Member
public:
  // @cmember Duplica un TDate.
  virtual TObject* dup() const;
  // @cmember Ritorna la data in formato di stringa (anche in formato ANSI)
  char* string(TDate_mgafmt year  = full, char sep = '-', TDate_mgafmt day = full, TDate_mgafmt month = full, TDate_order ord = gma_date) const ;
  // @cmember Ritorna la data come numero giuliano
  long date2julian() const;
  // @cmember Trasforma un numero giuliano in data ANSI
  long julian2date(long julian) const;
  // @cmember Ritorna la data come numero ANSI
  long date2ansi() const { return _val; }
  
  // @cmember Ritorna il giorno
  int day() const ;
  // @cmember Ritorna il mese
  int month() const ;
  // @cmember Ritorna l'anno
  int year() const ;
  // @cmember Ritorna il giorno della settimana (1 = Lunedi, 7 = domenica)
  int wday() const ;
  // @cmember Ritorna la settimana dell'anno
  int week() const ;
  // @cmember Ritorna la settimana e l'anno considerando le settimane complete <p complete> o no
  void get_week_year(int &weekd, int &yeard, bool complete);
  // @cmember Aggiunge dei mesi
  void addmonth(int nmonth = 1);
  // @cmember Aggiunge degli anni
  void addyear(int nyear = 1);
  // @cmember Controlla se si tratta di una data corretta
  bool ok() const;
  // @cmember Controlla se la stringa passata e' una data corretta
  static bool isdate(const char*);

  // @cmember Ritorna l'ultimo giorno possibile del mese
  static int last_day(int month, int year);
  // @cmember Controlla se il giorno e' l'ultimo del mese
  bool is_end_month();
  // @cmember Setta il giorno del mese all'ultimo possibile
  void set_end_month();
  // @cmember Controlla se la data � nulla
  bool empty() const ;
  
  // @cmember Setta la il giorno
  void set_day(int n);
  // @cmember Setta il mese
  void set_month(int n);
  // @cmember Setta l'anno
  void set_year(int n);
  // @cmember Permette di stabilire il criterio di formattazione delle date
  void set_format(const char* f);
  
  // @cmember Incrementa la data di un certo numero di giorni
  TDate& operator +=(long nday);
  // @cmember Decrementa la data di un certo numero di giorni
  TDate& operator -=(long nday)
  { return operator+=(-nday); }
  // @cmember Incrementa la data di un giorno
  TDate& operator ++()
  { return operator +=(1L); }
  // @cmember Decrementa la data di un giorno
  TDate& operator --()
  { return operator +=(-1L); }

  // @cmember Stampa sull'output passato la data
  void print_on(ostream& out) const ;
  // @cmember Legge dall'input passato la data
  void read_from(istream& in) ;

  // @cmember void | operator const char*() const | | Ritorna la data in formato stringa (chiama <mf TDate::String>)
  operator const char*() const ;
  // @cmember Assegna la data passata come stringa
  TDate& operator =(const char* s);
  // @cmember Assegna la data passato come valore numerico ANSI
  TDate& operator =(long val);
  // @cmember Assegna la data passata come oggetto data
  TDate& operator =(const TDate& d)
  { _val = d._val; return *this;}

  // @cmember Costruttore
  TDate(const TDate& d);
  // @cmember Costruttore
  TDate(long l = NULLDATE);
  // @cmember Costruttore
  TDate(const char* s);
  // @cmember Costruttore
  TDate(int day, int month, int year);
};


// @doc EXTERNAL

// @class TFormatted_date | Classe per la definizione di date con un formato
//
// @base public | TDate
class TFormatted_date : public TDate

// @author:(INTERNAL) Guido

// @access:(INTERNAL) Private Member
{
  
  // @cmember:(INTERNAL) Formato per tutti i pezzettini
  char _format[5]; 

  // @access Public Member
public:  
  // @cmember Permette di stabilire il criterio di formattazione delle date
  void set_format(const char* f);
  // @cmember Ritorna la data in formato di stringa (vedi <mf TDate::string>)
  const char* string() const;

  // @cmember Controlla se due stringhe contenenti date coincidono (TRUE se uguali)
  TFormatted_date& operator =(const char* s)
  { TDate::operator =(s); return *this; }
  // @cmember Controlla se due oggetti TDate coincidono (TRUE se uguali)
  TFormatted_date& operator =(const TDate& d)
  { TDate::operator =(d); return *this; }
  // @cmember Controlla se due oggetti TFormatted_date coincidono (TRUE se uguali)
  TFormatted_date& operator =(const TFormatted_date& d)
  { TDate::operator =(d); set_format(d._format); return *this; }

  // @cmember Costruttore (accetta la definizione di giorno, mese e anno)
  TFormatted_date(int day = 0, int month = 0, int year = 0, const char* f = "1444-");
  // @cmember Costruttore (accetta una TDate)
  TFormatted_date(const TDate& d, const char* f = "1444-");
  // @cmember Costruttore
  TFormatted_date(const TFormatted_date& d);
};

TDate operator +(const TDate& a, long nday) ;
TDate operator +(const long nday, const TDate& b) ;
TDate operator -(const TDate& a, long nday) ;
long   operator -(const TDate& a, const TDate& b) ;

// @doc EXTERNAL

// @func inline bool | operator <gt> | Controlla se una data e' minore di un'altra
//
// @rdesc Ritorna i seguenti valori
//
// @flag TRUE | Se <p a> e' maggiore di <p b>
// @flag FALSE | Se <p a> non e' maggiore di <p b>
inline bool operator <(
  const TDate& a,  // @parm Prima data da confrontare
  const TDate& b)  // @parm Secondo data da confrontare
{ return a._val < b._val;}

// @doc EXTERNAL

// @func inline bool | operator <lt> | Controlla se una data e' maggiore di un'altra
//
// @rdesc Ritorna i seguenti valori
//
// @flag TRUE | Se <p a> e' minore di <p b>
// @flag FALSE | Se <p a> non e' minore di <p b>
inline bool operator >(
  const TDate& a,  // @parm Prima data da confrontare
  const TDate& b)  // @parm Secondo data da confrontare
{ return a._val > b._val;}

// @doc EXTERNAL

// @func inline bool | operator <lt>= | Controlla se una data e' minore o ugaule ad un'altra
//
// @rdesc Ritorna i seguenti valori
//
// @flag TRUE | Se <p a> e' minore o uguale a <p b>
// @flag FALSE | Se <p a> e' maggiore di <p b>
inline bool operator <=(
  const TDate& a,  // @parm Prima data da confrontare
  const TDate& b)  // @parm Secondo data da confrontare
{ return a._val <= b._val;}

// @doc EXTERNAL

// @func inline bool | operator <gt>= | Controlla se una data e' maggiore o uguale ad un'altra
//
// @rdesc Ritorna i seguenti valori
//
// @flag TRUE | Se <p a> e' maggiore o ugaule a <p b>
// @flag FALSE | Se <p a> e' minore di <p b>
inline bool operator >=(
  const TDate& a,  // @parm Prima data da confrontare
  const TDate& b)  // @parm Secondo data da confrontare
{ return a._val >= b._val;}

// @doc EXTERNAL

// @func inline bool | operator == | Controlla se 2 date sono uguali
//
// @rdesc Ritorna i seguenti valori
//
// @flag TRUE | Se le due date sono uguali
// @flag FALSE | Se le due date non sono uguali
inline bool operator ==(
  const TDate& a,  // @parm Prima data da confrontare
  const TDate& b)  // @parm Secondo data da confrontare
{ return a._val == b._val;}

// @doc EXTERNAL

// @func inline bool | operator != | Controlla se 2 date sono diverse
//
// @rdesc Ritorna i seguenti valori
//
// @flag TRUE | Se le due date sono diverse
// @flag FALSE | Se le due date non sono diverse
inline bool operator !=(
  const TDate& a,  // @parm Prima data da confrontare
  const TDate& b)  // @parm Secondo data da confrontare
{ return a._val != b._val;}

void swap(TDate& a, TDate& b) ;
const TDate& fnc_min(const TDate& a, const TDate& b) ;
const TDate& fnc_max(const TDate& a, const TDate& b) ;

const char* itom(int month);
const char* itow(int dayofweek);

const TDate botime(0,0,0), eotime(31,12,2050);

#endif // __DATE_H