/*
 * StringToSysTime.c - These functions are used to convert a date string string
 * 					   to a SYSTEMTIME structure.
 *
 * 					   by nabiy . http://nabiy.sdf1.org
 */

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>

#include "StringToSysTime.h"

_Bool IsValidDate(int CCYY, int MM, int DD)
/*
 * Checks if a date is valid. returns true if valid false otherwise.
 *
 * [in] Year, Month, and Day values as integers.
 *
 */
{
#define LEAPYEAR (CCYY % 100 == 0 && CCYY % 400 == 0) || (CCYY % 100 != 0 && CCYY % 4 == 0)
	int maxDay ;

	switch (MM) {
        case 4:
        case 6:
        case 9:
        case 11:
            maxDay = 30;
            break ;
        case 2:
            if ( LEAPYEAR ) {
                maxDay = 29 ;
                break ;
            } else {
                maxDay = 28 ;
                break ;
            }
        default:
            maxDay = 31 ;
    }

    if ((DD < 1) || (DD > maxDay) )
        return 0 ;
    if ((MM < 1) || (MM > 12))
        return 0 ;
    if ((CCYY < 1601) || (CCYY > 30827))
        return 0 ;

    return 1 ;
}

_Bool IsValidTime(int hh, int mm, int SS)
/*
 * Checks if a time is valid. returns true if valid false otherwise.
 *
 * [in] Hour, Minute, and Second values as integers.
 *
 */
{
    if ((hh < 0) || (hh > 23) )
        return 0 ;
    if ((mm < 0) || (mm > 59))
        return 0 ;
    if ((SS < 0) || (SS > 59))
        return 0 ;

    return 1 ;
}

_Bool StringToSysTime( LPSYSTEMTIME lpSystemTime, const LPSTR szDate)
/*
 * Convert a date string to a SYSTEMTIME structure. The date string must be
 * in [[CC]YY]MMDDhhmm[.SS] format.
 *
 * [out] pointer to SYSTEMTIME structure to receive the converted system time. 
 * 
 * [in] pointer to a date string in  [[CC]YY]MMDDhhmm[.SS] format to be 
 *      converted to system time.
 */
{
	WORD stamp ;
	TCHAR temp[3] ;
	TCHAR tempYr[5] ;
	SYSTEMTIME stSysTime ;
	stamp = _tcslen(szDate) ;

	if ( ( szDate[stamp - 3] == '.') && ( stamp == 15 ) 
			|| (szDate[stamp - 3] != '.') && (stamp == 12) ) {
		_stprintf(tempYr, sizeof(tempYr), __T("%c%c%c%c"), szDate[0], 
				szDate[1], szDate[2], szDate[3]) ;
		lpSystemTime->wYear = (WORD) atoi(tempYr) ;
		_stprintf(temp, sizeof(temp), __T("%c%c"), szDate[4], szDate[5]) ;
		lpSystemTime->wMonth = (WORD) atoi(temp) ;
		_stprintf(temp, sizeof(temp), __T("%c%c"), szDate[6], szDate[7]) ;
		lpSystemTime->wDay = (WORD) atoi(temp) ;
		_stprintf(temp, sizeof(temp), __T("%c%c"), szDate[8], szDate[9]) ;
		lpSystemTime->wHour = (WORD) atoi(temp) ;
		_stprintf(temp, sizeof(temp), __T("%c%c"), szDate[10], szDate[11]) ;
		lpSystemTime->wMinute = (WORD) atoi(temp) ;
		if ( szDate[stamp - 3] == '.') {
			_stprintf(temp, sizeof(temp), __T("%c%c"), szDate[13], szDate[14]) ;
			lpSystemTime->wSecond = (WORD) atoi(temp) ;
		}
	} else if ( ( szDate[stamp - 3] == '.') && ( stamp == 13 ) 
			|| (szDate[stamp - 3] != '.') && (stamp == 10) ) {
		// Only YY. We use the default century.
		_stprintf(temp, sizeof(temp), __T("%c%c"), szDate[0], szDate[1]) ;
		if ( atoi(temp) > 68 && atoi(temp) < 100)
			_stprintf(tempYr, sizeof(tempYr), __T("19%s"), temp) ;
		else if ( atoi(temp) > 0 && atoi(temp) < 69)
			_stprintf(tempYr, sizeof(tempYr), __T("20%s"), temp) ;
		lpSystemTime->wYear = (WORD) atoi(tempYr) ;

		_stprintf(temp, sizeof(temp), __T("%c%c"), szDate[2], szDate[3]) ;
		lpSystemTime->wMonth = (WORD) atoi(temp) ;
		_stprintf(temp, sizeof(temp), __T("%c%c"), szDate[4], szDate[5]) ;
		lpSystemTime->wDay = (WORD) atoi(temp) ;
		_stprintf(temp, sizeof(temp), __T("%c%c"), szDate[6], szDate[7]) ;
		lpSystemTime->wHour = (WORD) atoi(temp) ;
		_stprintf(temp, sizeof(temp), __T("%c%c"), szDate[8], szDate[9]) ;
		lpSystemTime->wMinute = (WORD) atoi(temp) ;
		if ( szDate[stamp - 3] == '.') {
			_stprintf(temp, sizeof(temp), __T("%c%c"), szDate[11], szDate[12]) ;
			lpSystemTime->wSecond = (WORD) atoi(temp) ;
		}
	} else if ( ( szDate[stamp - 3] == '.') && ( stamp == 11 ) 
			|| (szDate[stamp - 3] != '.') && (stamp == 8) ) {
		// There is no CCYY in the string we should get the year from  the system.
		GetSystemTime (&stSysTime) ;
		lpSystemTime->wYear = stSysTime.wYear ;
		_stprintf(temp, sizeof(temp), __T("%c%c"), szDate[0], szDate[1]) ;
		lpSystemTime->wMonth = (WORD) atoi(temp) ;
		_stprintf(temp, sizeof(temp), __T("%c%c"), szDate[2], szDate[3]) ;
		lpSystemTime->wDay = (WORD) atoi(temp) ;
		_stprintf(temp, sizeof(temp), __T("%c%c"), szDate[4], szDate[5]) ;
		lpSystemTime->wHour = (WORD) atoi(temp) ;
		_stprintf(temp, sizeof(temp), __T("%c%c"), szDate[6], szDate[7]) ;
		lpSystemTime->wMinute = (WORD) atoi(temp) ;
		if ( szDate[stamp - 3] == '.') {
			_stprintf(temp, sizeof(temp), __T("%c%c"), szDate[9], szDate[10]) ;
			lpSystemTime->wSecond = (WORD) atoi(temp) ;
		}
	} else {
		// if we get this far it is not in the correct format and we return error
		return 0 ;
	}

	// SS is optional. if it does not exist we set it to zero.
	if ( szDate[stamp - 3] != '.')
		lpSystemTime->wSecond = 0 ;
	lpSystemTime->wMilliseconds = 0 ;

	// is this a valid date?
	if (!IsValidDate(lpSystemTime->wYear, lpSystemTime->wMonth, lpSystemTime->wDay) 
			|| !IsValidTime(lpSystemTime->wHour, lpSystemTime->wMinute, 
				lpSystemTime->wSecond) )
		return 0 ;

	return 1 ;
}
