// Copyright 2020 Siemens Digital Industries Software
// ==================================================
// Copyright 2015
// Siemens Product Lifecycle Management Software Inc.
// All Rights Reserved.
// ==================================================
// Copyright 2020 Siemens Digital Industries Software

#ifndef TEAMCENTER_DATETIME_HXX
#define TEAMCENTER_DATETIME_HXX

#include <string>
#include <ctime>
#include <unidefs.h>
#include <base_utils/libbase_utils_exports.h>



namespace Teamcenter
{
    class DateTime;
}


class BASE_UTILS_API Teamcenter::DateTime
{
public:

    /**
     * Returns an instance of the Null DateTime object.
     * This is the client equivalent of the
     * Teamcenter POM  date_t constant returned by the function POM_null_date().
     */
    static const DateTime getNullDate();


    /**
     * Default constructor creating an instance with the current date and time
     */
    DateTime();

    /**
     * Construct a DateTime for the give time_t value (seconds elapsed since Jan 1, 1970, local time)
     *
     * @param time seconds elapsed since Jan 1, 1970
     */
    DateTime( time_t time );

    /**
     * Copy constructor from another instance of DateTime.

     * @param dateTime Existing DateTime value.
     */
    DateTime(const DateTime& dateTime);

    /**
     * Copy constructor from instance of date_t (local time).

     * @param aDatetype Existing date_t value.
     */
    DateTime(const date_t& aDatetype);

    /**
     * Construct a date by parsing a string with the format yyyy-MM-ddThh:mm:ss zz:zz.
     * <pre>
     * 2005-05-20T14:32:05-08:00    
     * Where the -08:00 is minus 8 hours from GTM (Pacific Standard Time).
     * The time-zone offset may exclude the ':'
     * 2005-05-20T14:32:05-0800
     *</pre> 
     * An empty string will construct a Null date (getNullDate()) instance.
     *
     * @param time String to parse (yyyy-MM-ddThh:mm:ss zz:zz).
     */
    DateTime( const std::string& time );


    /**
     * Construct a date from the given local time input values.
     *
     * @param year       yyyy
     * @param month      1-12 (January = 1)
     * @param day        1-31
     * @param hour       0-23
     * @param minutes    0-59
     * @param seconds    0-59
     */
    DateTime ( int year, int month, int day, int hour = 0, int minutes = 0, int seconds = 0 );

    ~DateTime(){};


    /**
     * Returns the date in a string with the format yyyy-MM-ddThh:mm:ss zz:zz
     *
     * @return The date as a string
     */
    std::string toString( ) const;

    /**
     * Returns the date in a string with the given format.
     *
     * @param format Format string with codes defined by the strftime function
     *        ( i.e. %Y = year in decimal, with the century)
     *
     * @return The date as a string
     */
    std::string toString( const std::string& format ) const;

    /**
     * Create a DateTime from a string with the format yyyy-MM-ddThh:mm:ss zz:zz.
     * <pre>
     * 2005-05-20T14:32:05-08:00    
     * Where the -08:00 is minus 8 hours from GTM (Pacific Standard Time).
     * The time-zone offset may exclude the ':'
     * 2005-05-20T14:32:05-0800
     *</pre>
     * An empty string will construct a Null date (getNullDate()) instance.
     *
     * @param time String to parse (yyyy-MM-ddThh:mm:ss zz:zz)
     */
    DateTime convertStringToDate(const std::string& value);

     /**
     * Returns the date as seconds elapsed since Jan 1, 1970, local time.
     * Any dates prior to 1970 will return a -1, this includes the NullDate.
     *
     * @return seconds elapsed since Jan 1, 1970, local time
     */
    time_t toTime() const;

    /**
     * Returns the timezone offset of this date.
     *
     * @return offset from GMT (minutes)
     */
    int  timeZoneOffset() const;

    /**
     * @return The four digit year, local time
     */
    int  year  () const          {return m_dateTime.year;}       

    /**
     * @return The month (1..12), local time
     */
    int  month () const          {return m_dateTime.month + 1;}      
    /**
     * @return The day (1..31), local time
     */
    int  day   () const          {return m_dateTime.day;}           
    /**
     * @return The hour (0..23), local time
     */
    int  hour  () const          {return m_dateTime.hour;}          
    /**
     * @return The minute (0..59), local time
     */
    int  minute() const          {return m_dateTime.minute;}        
    /**
     * @return The seconds (0..59), local time
     */
    int  second() const          {return m_dateTime.second;}        

    int  year  (int y)           {return (m_dateTime . year   = static_cast<short>(y));}
    int  month (int m)           {return (m_dateTime . month  = static_cast<byte>(m -1)) + 1;}
    int  day   (int d)           {return (m_dateTime . day    = static_cast<byte>(d));}
    int  hour  (int h)           {return (m_dateTime . hour   = static_cast<byte>(h));}
    int  minute(int m)           {return (m_dateTime . minute = static_cast<byte>(m));}
    int  second(int s)           {return (m_dateTime . second = static_cast<byte>(s));}

    /**
     * @return A date_t struct (local time) representing the current DateTime.
     */
    operator date_t() const      { return (date_t)m_dateTime;}

    bool operator ==(const DateTime& that) const;
    bool operator !=(const DateTime& that) const {return !operator==(that);}

    bool operator  >(const DateTime& that) const;
    bool operator  <(const DateTime& that) const;
    bool operator >=(const DateTime& that) const {return !operator<(that);}
    bool operator <=(const DateTime& that) const {return !operator>(that);}

    DateTime& operator  =( const DateTime& that );
    DateTime  operator  +( const DateTime& that ) const;
    DateTime  operator  -( const DateTime& that ) const;
    DateTime  operator +=( const DateTime& that );
    DateTime  operator -=( const DateTime& that );

    /**
     * Returns the local time-zone offset from GMT (minutes).
     *
     */
    static int getTimeZoneOffset();
    static int getTimeZoneStandardOffset();
    int isValid() const;
    int isLeapYear(int nYear) const;

    DateTime& init(const DateTime& d2);
    DateTime& init( int year, int month, int day, int hour = 0, int minutes = 0, int seconds = 0 );

private:
    void initStatics()const;
    int  getLocalGMTOffset( int hour, int minute) const;
    bool isDayLight() const;

    static tm dateElementsToTm( const date_t& dateTime);
    static date_t tmToDate( const tm& date);

    // Internal date structure, in local  time
    date_t           m_dateTime;


    static std::string  s_NullDateString;
    static int          s_standardOffset;
    static int          s_daylightOffset;


};

#include <base_utils/libbase_utils_undef.h>
#endif
