
#ifndef __CDATE_H__
#define __CDATE_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#ifndef WIN32
#include <unistd.h>
#include <sys/time.h>
#include <pthread.h>
#endif

#include "cstring.h"
#include "exception.h"

class CDateArray;

//============================================================================
class V2_CLASS_API CDate
{
private:
	char m_szDate[8+1];
	bool m_bSet;
public:
	enum E_Dir { BACKWARD=0, FORWARD };

	CDate();
	CDate(const char *p_szDate);
	CDate(const int p_iDate);
	CDate(const int p_iYear, const int p_iMonth, const int p_iDay);
	CDate(const CDate &p_Obj);
	~CDate();
	void Init();
	void SetNull();
	bool IsValid() const { return m_bSet; }
	void Set(const char *p_szDate);
	void Set(const int p_iDate);
	void SetAsToday();

	int Year() const {
		return (int)(atoi(m_szDate) / 10000);
	}

	int Month() const {
		return (int)((atoi(m_szDate) % 10000) / 100);
	}

	int Day() const {
		return (int)(atoi(m_szDate) % 100);
	}

	const char *ToStr() const {
		return m_szDate;
	}

	CString ToFmtStr(const char *p_szSep="/") const {
		return (m_bSet) ? CFormat("%.4s%s%.2s%s%.2s", m_szDate, p_szSep, &m_szDate[4], p_szSep, &m_szDate[6]) : CString("");
	}

	CString Repr() const {
		return (m_bSet) ? CFormat("<CDate: %.8s>", (char *)m_szDate) : CString("<CDate: unset>");
	}

	int GetSize() const {
		return m_bSet ? 8 : 0;
	}

	// < : -1, == : 0, > : 1
	int Compare(const CDate &date) const {
		return memcmp(m_szDate, date.m_szDate, 8);
	}

	int Compare(const char *p_szStr) const {
		return memcmp(m_szDate, p_szStr, 8);
	}

	CDate &operator=(const CDate &p_Obj) {
		Set((const char *)p_Obj.m_szDate);
		m_bSet = p_Obj.m_bSet;
		return *this;
	}

	CDate &operator=(const char *p_szDate) {
		Set(p_szDate);
		return *this;
	}

	bool operator==(const CDate &date) const { return Compare(date) == 0; }
	bool operator!=(const CDate &date) const { return Compare(date) != 0; }
	bool operator< (const CDate &date) const { return Compare(date) <  0; }
	bool operator<=(const CDate &date) const { return Compare(date) <= 0; }
	bool operator> (const CDate &date) const { return Compare(date) >  0; }
	bool operator>=(const CDate &date) const { return Compare(date) >= 0; }

	bool operator==(const char *p_szStr) const { return Compare(p_szStr) == 0; }
	bool operator!=(const char *p_szStr) const { return Compare(p_szStr) != 0; }
	bool operator< (const char *p_szStr) const { return Compare(p_szStr) <  0; }
	bool operator<=(const char *p_szStr) const { return Compare(p_szStr) <= 0; }
	bool operator> (const char *p_szStr) const { return Compare(p_szStr) >  0; }
	bool operator>=(const char *p_szStr) const { return Compare(p_szStr) >= 0; }

	void AddYear(int p_iYear, bool p_bLastDayAdjust=false);
	void AddMonth(int p_iMonths, bool p_bLastDayAdjust=false);
	void AddDay(int p_iDays);
	CDate GetLastDateOfMonth();
	CDate GetBizDateAdjusted(E_Dir p_eDir=CDate::FORWARD, CDateArray *p_pHolidays=NULL);

	int GetDayOfWeek() {
		return CDate::GetDayOfWeek(Year(), Month(), Day());
	}

	int GetFirstDayOfMonth() {
		return CDate::GetDayOfWeek(Year(), Month(), 1);
	}

	bool IsLeapYear() {
		int y = Year();
		return (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0));
	}

	// ==========================================================================
	// static functions
	static bool IsLeapYear(int p_iYear) {
		return (((p_iYear % 4 == 0) && (p_iYear % 100 != 0)) || (p_iYear % 400 == 0));
	}

	static int GetDayOfWeek(int p_iYear, int p_iMonth, int p_iDay);

	static int GetFirstDayOfMonth(int p_iYear, int p_iMonth) {
		return CDate::GetDayOfWeek(p_iYear, p_iMonth, 1);
	}

	static int GetMonthDays(int p_iYear, int p_iMonth);

	static int GetTotalDays(const CDate &p_nDate);	// total days from 0001.01.01 to p_nDate
	static int GetDaysDiff(const CDate &p_nStart, const CDate &p_nEnd);
};


//============================================================================
class V2_CLASS_API CTime {
private:
#ifdef WIN32
	struct {
		time_t tv_sec;
		long tv_usec;
	} m_tval;
#else
	struct timeval m_tval;
#endif
	struct tm m_tm;
	bool m_bSet;

public:
	CTime();
	~CTime();
	void SetAsNow();
	CString ToFmtStr(const char *p_szFmt="h:m:s") const;

	bool IsValid() const { return m_bSet; }
	int GetHour() const { return m_tm.tm_hour; }
	int GetMin() const { return m_tm.tm_min; }
	int GetSec() const { return m_tm.tm_sec; }
	int GetUSec() const { return m_tval.tv_usec; }
	time_t GetTimeVal() const { return m_tval.tv_sec; }
	struct tm GetTmStruct() const { return m_tm; }
	CString Repr() const;
	static CString GetTimeStamp(const char *p_szFmt="YMD hms");
};

#endif	// __CDATE_H__
