/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                          CDateTime.h  -  description
                             -------------------
    begin                : Tue Dec 14 1999
    copyright            : (C) 1999-2006 by Alexey Parshin
    email                : alexeyp@gmail.com
 ***************************************************************************/

/***************************************************************************
   This library is free software; you can redistribute it and/or modify it 
   under the terms of the GNU Library General Public License as published by
   the Free Software Foundation; either version 2 of the License, or (at 
   your option) any later version.

   This library is distributed in the hope that it will be useful, but 
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library
   General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; if not, write to the Free Software Foundation, 
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.

   Please report all bugs and problems to "alexeyp@gmail.com"
 ***************************************************************************/

#ifndef __CDATETIME_H__
#define __CDATETIME_H__

#include <sptk3/sptk.h>
#include <string>

namespace sptk {

   /// @addtogroup utility Utility Classes
   /// @{

	class CDateTime;
	class CDateTimeFormat;

   /// @brief Date and Time value.
   ///
   /// Represents the date and time value. This value is stored as
   /// a floating point number. Allows to synchronize the Now() time
   /// with the external date/time, without affecting the local host 
   /// system time.
	class SP_EXPORT CDateTime {
		friend class CDateTimeFormat;
	protected:

      /// Internal decode date operation into y,m,d
		static void   decodeDate(const double dt,short& y,short& m,short& d);

      /// Internal decode time operation into h,m,s,ms
		static void   decodeTime(const double dt,short& h,short& m,short& s,short& ms);

      /// Internal encode date operation from y,m,d
		static void   encodeDate(double &dt,short y=0,short m=0,short d=0);

      /// Internal encode date operation from string
		static void   encodeDate(double &dt,const char *dat);

      /// Internal encode timee operation from h,m,s,ms
		static void   encodeTime(double &dt,short h=0,short m=0,short s=0,short ms=0);

      /// Internal encode timee operation from string
		static void   encodeTime(double &dt,const char *tim);

      /// Returns true for the leap year
		static int    isLeapYear(const short year);

	protected:

		double                m_dateTime;             ///< Actual date and time value

      /// The offset from current' system time for synchronization
      /// with outside system
		static double         m_dateTimeOffset;    
		static bool           m_time24Mode;           ///< System's time mode
	public:

		static char           dateFormat[32];         ///< System's date format
		static char           fullTimeFormat[32];     ///< System's time format
		static char           shortTimeFormat[32];    ///< System's time format
		static char           datePartsOrder[4];      ///< System's date parts order 
		static char           dateSeparator;          ///< System's date separator
		static char           timeSeparator;          ///< System's time separator
		static std::string    weekDayNames[7];        ///< The locale-defined weekday names
		static std::string    monthNames[12];         ///< The locale-defined weekday names
		static std::string    timeZoneName;           ///< Time zone abbbreviastion
		static int            timeZoneOffset;         ///< Time zone offset from GMT in hours

	public:

      /// @brief Constructor
      /// @param y short, year
      /// @param m short, month
      /// @param d short, day
      /// @param h short, hour
      /// @param mm short, minute
      /// @param s short, second
		CDateTime (short y,short m,short d,short h=0,short mm=0,short s=0);

      /// @brief Constructor
      /// @param dateStr const char *, date string
		CDateTime (const char * dateStr);

      /// @brief Copy constructor
		CDateTime (const CDateTime &dt);

      /// @brief Constructor
      /// @param dt double, floating point date and time value
		CDateTime (const double dt=0);

      /// @brief Conversion to double
		operator double () const;

      /// @brief Assignment
		void operator = (const CDateTime& date);

      /// @brief Assignment
		void operator = (const char * dat);

      /// @brief Addition, another CDateTime
		CDateTime  operator + (CDateTime& dt);

      /// @brief Substruction, another CDateTime
		CDateTime  operator - (CDateTime& dt);

      /// @brief Increment by another CDateTime
		CDateTime& operator += (CDateTime& dt);

      /// @brief Decrement by another CDateTime
		CDateTime& operator -= (CDateTime& dt);

      /// @brief Increment by day, prefix
		CDateTime& operator ++ ();   

      /// @brief Increment by day, postfix
		CDateTime& operator ++ (int);

      /// @brief Decrement by day, prefix
		CDateTime& operator -- ();     

      /// @brief Decrement by day, postfix
		CDateTime& operator -- (int);  

      /// @brief Print the date into str
		void formatDate(char *str) const;

      /// @brief Print the date into str
		void formatTime(char *str,bool ampm=true,bool showSeconds=false) const;

      /// @brief Set the current date and time for this program only.
      ///
      /// The system time is not affected. Useful for synchronization between
      /// different hosts' programs.
		static void Now(CDateTime dt);

      /// @brief Reports the system date and time.
		static CDateTime System();

      /// @brief Reports the current date and time.
		static CDateTime Now();

      /// @brief Reports the current date.
		static CDateTime Date();           

      /// @brief Reports the current time.
		static CDateTime Time();           

      /// @brief Converts C time into CDateTime
		static CDateTime convertCTime(const time_t tt);

      /// @brief Reports the number of days in the month in this date (1..31)
		short daysInMonth() const;         

      /// @brief Reports the day of the week in this date (1..7)
		short dayOfWeek(void) const;       

      /// @brief Reports the day since the beginning of the year in this date
		short dayOfYear()  const;  

      /// @brief Reports the day of the week name in this date ('Sunday'..'Saturday')
		std::string dayOfWeekName(void) const;

      /// @brief Reports the month name in this date ('Sunday'..'Saturday')
		std::string monthName() const;

      /// @brief Reports the date as an integer
		unsigned date() const;

      /// @brief Reports the day of month (1..31)
		short day() const;

      /// @brief Reports the month number (1..12)
		short month() const;

      /// @brief Reports the year
		short year() const;
	public:

      /// @brief Returns date as a string
		std::string dateString() const;

      /// @brief Returns time as a string
		std::string timeString(bool showSeconds=false) const;

      /// @brief Returns date and time as a string
		operator std::string () const { return dateString() + " " + timeString(); }
	public:

      /// @brief Decodes date into y,m,d
		void decodeDate(short *y,short *m,short *d) const;

      /// @brief Decodes time into h,m,s,ms
		void decodeTime(short *h,short *m,short *s,short *ms) const;

      /// @brief Returns system's time mode.
		static bool time24Mode() { return m_time24Mode; }

      /// @brief Sets system's time mode
		static void time24Mode(bool t24mode);          
	};
   /// @}
}

/// @brief Compares CDatetime values
bool operator <  (const sptk::CDateTime &dt1, const sptk::CDateTime &dt2);

/// @brief Compares CDateTime values
bool operator <= (const sptk::CDateTime &dt1, const sptk::CDateTime &dt2);

/// @brief Compares CDateTime values
bool operator >  (const sptk::CDateTime &dt1, const sptk::CDateTime &dt2);

/// @brief Compares CDatetime values
bool operator >= (const sptk::CDateTime &dt1, const sptk::CDateTime &dt2);

/// @brief Compares CDatetime values
bool operator == (const sptk::CDateTime &dt1, const sptk::CDateTime &dt2);

/// @brief Compares CDatetime values
bool operator != (const sptk::CDateTime &dt1, const sptk::CDateTime &dt2);

/// @brief Adds two CDatetime values
sptk::CDateTime operator + (const sptk::CDateTime &dt1, const sptk::CDateTime &dt2);

/// @brief Subtracts two CDatetime values
sptk::CDateTime operator - (const sptk::CDateTime &dt1, const sptk::CDateTime &dt2);

#endif
