/*=================================================================
   Copyright (C) 2000 2013 BizStation Corp All rights reserved.

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

   This program 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software 
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
   02111-1307, USA.
=================================================================*/
#include <bzs/env/tstring.h>
#pragma hdrstop

#include "datetime.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <bzs/env/crosscompile.h>
#ifdef LINUX
#include <wchar.h>
#endif

#pragma package(smart_init)		// BCB package
#pragma warning(disable:4996)	// VC++ unsafe function

//Ansi & Unicode
#if (defined(_WIN32) && _MSC_VER)
	extern DWORD g_tlsiID_SC3;
#else
	__THREAD _TCHAR __THREAD_BCB g_date[30];
#endif

inline _TCHAR* databuf()
{
	#if (defined(_WIN32) && _MSC_VER)
		return (_TCHAR*)TlsGetValue(g_tlsiID_SC3);
	#else
		return g_date;
	#endif
}


namespace bzs
{
namespace rtl
{



int   GetDate(const _TCHAR* NowDate)
{
    int ret;
    ret = _ttol(NowDate+8);
    return ret;
}

int   GetYear(const _TCHAR* NowDate, bool PrevMonth)
{
    int ret;
    ret = _ttol(NowDate);
    if ((PrevMonth) && (GetMonth(NowDate, false) == 1))
        ret--;
    return ret;
}

int   GetMonth(const _TCHAR* NowDate, bool PrevMonth)
{
    int ret;
    ret = _ttol(NowDate+5);
    if (PrevMonth)
        ret--;
    if (ret == 0)
        ret = 12;

    return ret;
}

bool  IsUrudosi(int Year)
{
    if ((Year % 4) == 0)
    {
        if ((Year % 400) == 0)
            return true;
        else if ((Year % 100) == 0)
            return false;
        else
            return true;
    }
    return false;
}

bool GetDatefromYearSerialDays(int year, int Days, _TCHAR* date, bool nextYearRight)
{	
	//The date of the day counted from the beginning of the year is returned.
 	//if orver the year then return false.

    int mm;
    int dd = Days;
    for (mm=1; mm < 14;mm++)
    {
        switch (mm)
        {
        case 2:
            if(IsUrudosi(year))
                Days-=29;
            else
                Days-=28;
            break;
        case 4:
        case 6:
        case 9:
        case 11:
            Days-=30;break;
        default:
            Days-=31;
        }
        if (Days <= 0)
            break;
        dd=Days;
    }
    bool ret= true;
    if ((dd>31)|| (mm==13))
    {
        if (nextYearRight)
        {
            year += 1;
            mm = 1;
        }else
        {//for old program
            dd = 31;
            mm--;
        }
        ret= false;
    }
    _stprintf(date,_T("%04d/%02d/%02d"), year,mm,dd);
    return ret;
}

//---------------------------------------------------------------------------
int JDate2NumOLD(const _TCHAR* date)
{//1900/01/01 = 2415021
	int yy = GetYear(date,false);
	int mm = GetMonth(date,false);
	int dd = GetDate(date);
	int i;

	//The number of leap years 
	int n = 2415020;
	for (i=1900; i < yy; i+= 4)
	{
		if(IsUrudosi(i))
			n+=1;
	}
	n+= (yy - 1900 ) * 365;
	for (i=1; i < mm ;i++)
	{
		switch(i)
		{
		 case 2:
			if(IsUrudosi(yy))
				n+=29;
			else
				n+=28;
			break;
		 case 4:
		 case 6:
		 case 9:
		 case 11:
			n+=30;
			break;
		 default:
			n+=31;
		}
	}
	n+=dd;
	return n;
}
#ifdef _WIN32
//---------------------------------------------------------------------------
int JDate2Num(const _NTCHAR* date)
{
    #ifdef _UNICODE
        wchar_t buf[20];
        MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, date, -1, buf, 20);
    #else
        char buf[20];
        wtoa(buf, date, 20);
    #endif
    return JDate2Num(buf);
}
#endif
//---------------------------------------------------------------------------
int JDate2Num(const _TCHAR* date)
{//1980/01/01 = 2444240
	int yy = GetYear(date,false);
    if (yy < 1980)
        return JDate2NumOLD(date);

	int mm = GetMonth(date,false);
	int dd = GetDate(date);
	int i;


	//The number of leap years 
	int n = 2444239;
	for (i=1980; i < yy; i+= 4)
	{
		if(IsUrudosi(i))
			n+=1;
	}
	n+= (yy - 1980 ) * 365;
	for (i=1; i < mm ;i++)
	{
		switch(i)
		{
		 case 2:
			if(IsUrudosi(yy))
				n+=29;
			else
				n+=28;
			break;
		 case 4:
		 case 6:
		 case 9:
		 case 11:
			n+=30;
			break;
		 default:
			n+=31;
		}
	}
	n+=dd;
	return n;
}
//---------------------------------------------------------------------------
_TCHAR* JNum2DateOLD(int n)
{//1900/01/01 = 2415021
	bool uru = false;
	if (n < 2415021)
		return NULL;

	int yy = 1900;
	n -= 2415020;
	while (1)
	{
		if(uru)
		{
			if (n <= 366)
				break;
		}
		else
		{
			if (n <= 365)
				break;
		}
		if(uru)
			n -= 366;
		else
			n -= 365;
		yy++;
		uru = IsUrudosi(yy);
	}
	GetDatefromYearSerialDays(yy, n, databuf());
	return databuf();
}

//---------------------------------------------------------------------------
const _TCHAR* JNum2Date(int n)
{//1980/01/01 = 2444240
	bool uru = true;
	if (n < 2444240)
        return JNum2DateOLD(n);

	int yy = 1980;
	n -= 2444239;
	while (1)
	{
		if(uru)
		{
			if (n <= 366)
				break;
		}
		else
		{
			if (n <= 365)
				break;
		}
		if(uru)
			n -= 366;
		else
			n -= 365;
		yy++;
		uru = IsUrudosi(yy);
	}
	GetDatefromYearSerialDays(yy, n, databuf());
	return databuf();
}

//---------------------------------------------------------------------------
long StrToLongDate(_TCHAR* strdat)
{   //Conver string date to long. ex : 20011231
	 _TCHAR buf[9];
	 _tcsncpy(buf, strdat, 4);
	 _tcsncpy(buf + 4,strdat + 5, 2);
	 _tcsncpy(buf + 6,strdat + 8, 2);
	 buf[8] = 0x00;
	 return _ttol(buf);
}
//---------------------------------------------------------------------------
_TCHAR* LongToStrDate(long ldat , _TCHAR* strdat)
{ //Conver long date to string date�B
  //No check long date is valid.
	 _TCHAR buf[11];
	 if (ldat == 0)
		_tcscpy(strdat,_T("0000/00/00"));
	 else
	 {
		_stprintf_s(buf, 11, _T("%08ld"),ldat);

		_tcsncpy(strdat, buf, 4);
		strdat[4] = '/';
		_tcsncpy(strdat + 5, buf + 4, 2);
		strdat[7] = '/';
		_tcsncpy(strdat + 8, buf + 6, 2);
		strdat[10] = 0x00;
	 }
	return strdat;
}
//---------------------------------------------------------------------------
_TCHAR* LongToStrTime(long ltime , _TCHAR* strdat)
{ //Conver long time to string time�B
  //No check long time is valid.
	_TCHAR buf[9];
	_stprintf_s(buf, 9, _T("%ld"),ltime);
	_tcsncpy(strdat,buf,2);
	strdat[2] = ':';
	_tcsncpy(strdat + 3, buf + 2, 2);
	strdat[5] = ':';
	_tcsncpy(strdat + 6, buf + 4, 2);
	strdat[8] = 0x00;
	return strdat;
}
//---------------------------------------------------------------------------
const char* dateTimeStr(char* buf, unsigned int bufsize)
{
	struct tm* date;
	time_t now;
	time(&now);
#ifdef __MINGW32__
	date = localtime(&now);
#else
	struct tm tmp;
	date = &tmp;
	localtime_x(date, &now);
#endif	
	sprintf_s(buf, bufsize, "%04d/%02d/%02d %02d:%02d:%02d"
			,date->tm_year + 1900, 	date->tm_mon + 1,date->tm_mday
			,date->tm_hour, date->tm_min, date->tm_sec);
	return buf;
}


}//namespace rtl
}//namespace bzs

#pragma warning(default:4996)