#pragma once
#include <ctime>

#include "GlobalDefs.h"
#include "struct.h"
#include <windows.h>

class SysTime
{
public:

   SysTime(void);
   bool IsValid(void);
	inline void Update(void);

   UINT16 Year(void) const  
      { return m_tm.tm_year < 1000 ? m_tm.tm_year + 1900 : m_tm.tm_year; }
   bool IsLeapYear(void);
   UINT8 Month(void) const    { return m_tm.tm_mon + 1; }   // 1-12
   const char* MonthStr(void) const 
      { return m_tm.tm_mon >= 0 && m_tm.tm_mon < 12 ? s_months[m_tm.tm_mon] : "Invalid"; }
   UINT8 Day(void) const      { return m_tm.tm_mday; }      // 1-31
   UINT16 Hour(void) const     { return m_tm.tm_hour; }      // 0-23
   UINT8 Minute(void) const   { return m_tm.tm_min; }       // 0-59
   UINT8 Second(void) const   { return m_tm.tm_sec; }       // 0-59
   UINT16 Millisecond(void) const   { return m_tm.m_nanoseconds / 1000000; }
   UINT32 Nanosecond32(void) const  { return m_tm.m_nanoseconds; }
	UINT16 DayofYear(void)		{ return m_tm.tm_yday; }

   UINT32 SecondsToday(void) const
      { return (m_tm.tm_hour * 60 + m_tm.tm_min) * 60 + m_tm.tm_sec; }
   UINT32 SecondsThisYear(void) const
      { return m_tm.tm_yday*3600*24 +  (m_tm.tm_hour * 60 + m_tm.tm_min) * 60 + m_tm.tm_sec; }
   double CalendarTime(void);

   // year is real year, month is 1-12, day is 1-31
   inline void Set(UINT16 year, UINT8 month, UINT8 day);
   inline void Set(UINT8 hour, UINT8 minute, UINT8 second, 
                   UINT16 millisecond, UINT16 microsecond);
   void SetNanoSeconds( UINT32 nsecs ){ m_tm.m_nanoseconds = nsecs; }
	// MS bug - doesn't account for DST 
	// To work around this issue, call SetLocalTime() twice in a row. The first call changes you to the correct DST setting, 
	// the second call sets the time. 
	void SysTime::Set( SYSTEMTIME *tm ){ SetLocalTime( tm );	SetLocalTime( tm );}
	void SysTime::Set( StructTimeStamp *pTm ){ memcpy( &m_tm, pTm, sizeof( StructTimeStamp ) ); }

   void Get(struct tm* _tm, UINT32* nsecs) const
      { _tm->tm_year  = m_tm.tm_year;
        _tm->tm_mon   = m_tm.tm_mon;
        _tm->tm_mday  = m_tm.tm_mday;
        _tm->tm_yday  = m_tm.tm_yday;
        _tm->tm_hour  = m_tm.tm_hour;
        _tm->tm_min   = m_tm.tm_min;
        _tm->tm_sec   = m_tm.tm_sec;
        *nsecs        = m_tm.m_nanoseconds;
		}
	StructTimeStamp *GetTimeStamp() { return &m_tm; }

   // rvalue must be earlier (less) than "this".
   SysTime operator-(const SysTime& rvalue) const;
   SysTime& operator-=(const SysTime& rvalue);   // faster than -

   SysTime operator+(const SysTime& rvalue) const;
   SysTime& operator+=(const SysTime& rvalue);   // faster than +
   bool operator<(const SysTime& rvalue);
   bool operator>(const SysTime& rvalue);
   bool operator<=(const SysTime& rvalue);
   bool operator>=(const SysTime& rvalue);
   bool operator==(const SysTime& rvalue);
   bool operator!=(const SysTime& rvalue);
   SysTime& operator=(const SysTime& rvalue)     { m_tm = rvalue.m_tm;   m_tm.m_nanoseconds = rvalue.m_tm.m_nanoseconds;  return *this; }

	void BuildDateHrMinSecName( char *fname, char *prefix, char *postfix )
	{
		Update();
		sprintf_s( fname, 128, "%s_%02d%02d%04d%s", prefix, Month(), Day(), Year(), postfix );
	}

private:
   void SecondsToday(UINT32 s);
   void ConvertYDayToMDay(void);
   void ConvertMDayToYDay(void);

   StructTimeStamp m_tm;
   //UINT32 m_nanoseconds;

   static const int s_mdays[];
   static const char* s_months[];
};


