//   Gestion de dates 
//        E. Aubourg       1995-2000
// DAPNIA/SPP (Saclay) / CEA    LAL - IN2P3/CNRS  (Orsay)

#ifndef DATES_SEEN
#define DATES_SEEN

#include <string.h>
#include <string>
#include <iostream>
#include "pexceptions.h"

// namespace SOPHYA {  

class TimeZone;
// <summary> Dates, conversions, operations </summary>
// Classe generale de date et heure, operation, TU/TL ...
class Date  {
public:
  // Enumerations jours et mois
  // <group>
  enum Jour {jour_Lundi=0, jour_Mardi, jour_Mercredi, jour_Jeudi, jour_Vendredi, jour_Samedi, jour_Dimanche};
  enum Mois {mois_Janvier=1, mois_Fevrier, mois_Mars, mois_Avril, mois_Mai, mois_Juin, mois_Juillet,
             mois_Aout, mois_Septembre, mois_Octobre, mois_Novembre, mois_Decembre};
  enum {kGMTTime=0, kLocalTime=1};
  // </group>  

  // Constructeur : maintenant 
  Date();
  // Constructeur : jours ecoules depuis 0/1/1901 0h TU
  Date(double);
  // Constructeur : "jj/mm/aa" ou "amjj", "hh:mm:ss"
  // topt : kGMTTime (par defaut) ou kLocalTime
  // <group>
  Date(const char*, const char* = 0, int topt=0); 
  Date(string const&, string const& = "", int topt=0); 
  // </group>
  // Constructeur : Jour Mois An, Heure Minutes Secondes
  Date(int J, int M, int A, int h, int m, double s);

  /*operator double() const;*/
  // Jours depuis le 0 janvier 1901 0h TU
  double GetDays() const;
  // Jours depuis le 0 janvier 1901 0h TU
  void Set(double);
  //  "jj/mm/aa" ou "amjj", "hh:mm:ss"
  // <group>
  void Set(const char*, const char* = 0, int topt=0);
  void Set(string const&, string const& = "", int topt=0);
  // </group>
  
  // Change de zone horaire.
  void SetTimeZone(TimeZone* tz);

  // Verifie si des parties de la date sont indeterminees
  // <group>
  // Date partiellement indeterminee
  bool UndetDate() const;
  // Date totalement indeterminee
  bool AllUndetDate() const;
  // Heure partiellement indeterminee
  bool UndetTime() const;
  // Heure totalement indeterminee
  bool AllUndetTime() const;
  // </group>

  // Conversion vers des chaines de caractere,
  // date en clair ou code Eros, heure, et temps sideral
  // en heure local ou GMT.
  // <group>
  void GetDateStr(char*, int tOpt=0) const;
  void GetDateCode(char*, int tOpt=0) const;
  void GetTimeStr(char*, int tOpt=0) const;
  void GetSidTStr(char*) const;
  
  string DateStr(int tOpt=0) const;
  string DateCode(int tOpt=0) const;
  string TimeStr(int tOpt=0) const;
  string SidTStr() const;
  // </group>

  // Jour de la semaine, jour_Lundi == 0
  int  DayOfWeek(int tOpt=0) const;
  
  // Ajoute ou soustrait un intervalle en jour et fraction de jour
  // <group>
  Date& operator += (double);
  Date& operator -= (double);

  friend Date operator + (Date const&, double);
  friend Date operator - (Date const&, double);
  // </group>
  
  // Nombre de jour (et fraction) entre deux dates
  friend double operator - (Date const&, Date const&);
  
  // Comparaisons entre dates
  // <group>
  friend bool operator == (Date const&, Date const&);
  friend bool operator <  (Date const&, Date const&);
  friend bool operator <= (Date const&, Date const&);
  friend bool operator >  (Date const&, Date const&);
  friend bool operator >= (Date const&, Date const&);
  friend bool operator != (Date const&, Date const&);
  // </group>
  
  // Impression
  friend ostream& operator << (ostream&, Date const&);

  // Nombre de jours dans le mois
  static short MonthDays(short mois, short annee);
  
  // Nombre de jours dans l'annee
  static short YearDays(short annee);
  
  // Ieme jourssem dans le mois
  // (2, jour_Dimanche, 5, 1996) : deuxieme dimanche de mai 96
  static short NthMonthDay(short i, short joursem, short mois, short annee);

  short JJ,MM,AA,hh,mm;
  double ss; 
  TimeZone* timeZone;
  int nuit;  // est-ce une date midi-midi ?

/* void GetSysTimeZone(); */
};

// <summary> Gestion des fuseaux horaires </summary>
// Classe de gestion des fuseaux horaires. Tient compte des heures d'ete.
class TimeZone  {
public:
  char code[4];
  char name[20];

  short  gmtOffset;

  short  hasDST;
  short  dstByWeekDay;
  short  dstStartDay, dstStartNum, dstStartMonth;   // -1 : le dernier, dstStartDay : apres cette date
  short  dstStopDay, dstStopNum, dstStopMonth;
  short  dstOffset;

  TimeZone();                 // Tente de deviner le timezone systeme
  TimeZone(const char*);      // Par nom
  void SetZone(const char*);
  int IsDst(Date const& date);
  int GetOffset(Date const& date);
};

extern TimeZone* gTimeZone;

// }  namespace SOPHYA

#endif
