/*
 * COPYRIGHT:   LGPL, See LGPL.txt in the top level directory
 * PROJECT:     ReactOS CRT library
 * FILE:        lib/sdk/crt/time/timezone.c
 * PURPOSE:     Implementation of time zone functions
 * PROGRAMERS:  Timo Kreuzer
 */
#include "precomp.h"

char _tz_is_set = 0;

/* buffers must hold 64 characters! */
static char tz_name[64] = "PST";
static char tz_dst_name[64] = "PDT";

long dst_begin = 0;
long dst_end = 0;

/******************************************************************************
 * \var _tzname
 */
char * _tzname[2] = {
  tz_name,
  tz_dst_name,
};

/******************************************************************************
 * \var _daylight
 */
int _daylight = 0;

/******************************************************************************
 * \name __p__daylight
 * \brief Returns a pointer to the _daylight variable;
 */
void *
__p__daylight(void)
{
   return &_daylight;
}

/******************************************************************************
 * \var _timezone
 * \brief
 */
long _timezone = 28800;

/******************************************************************************
 * \name __p__timezone
 * \brief Returns a pointer to the _timezone variable;
 */
long *
__p__timezone(void)
{
   return &_timezone;
}

/******************************************************************************
 * \var _dstbias
 * \brief
 */
long _dstbias = 0;

/******************************************************************************
 * \name __p__dstbias
 * \brief Returns a pointer to the _dstbias variable;
 */
long *
__p__dstbias(void)
{
    return &_dstbias;
}

/******************************************************************************
 * \name __p__tzname
 * \brief Returns a pointer to the _tzname buffer;
 */
char **
__p__tzname(void)
{
    return _tzname;
}

/******************************************************************************
 * \name _tzset
 * \brief Initializes the variables _daylight, _timezone, and _tzname from the
 *        "TZ" environment variable if available or else by calling
 *        GetTimeZoneInformation.
 * \sa http://msdn.microsoft.com/en-us/library/90s5c885.aspx
 */
void
_tzset(void)
{
    const char * str;

    if (_tz_is_set)
    {
        return;
    }

    /* Try to read the timezone from environment */
    str = getenv("TZ");
    if (str && str[0] != 0)
    {
        long hour = 0, min = 0, sec = 0;
        size_t len = strnlen(str, 16);
        int sign = 1;

        dst_begin = 0;

        for (;;)
        {
            /* Copy timezone name */
            strncpy(tz_name, str, 3);
            str += 3;
            len -= 3;

            if (len < 1) break;

            if (*str == '+' || *str == '-')
            {
                sign = *str == '-' ? -1 : 1;
                str++;
                len--;
            }

            if (len < 1) break;

            hour = atol(str);

            while (*str != 0 && *str != ':') str++;
            if (*str == 0) break;

            min = atol(++str);

            while (*str != 0 && *str != ':') str++;
            if (*str == 0) break;

            sec = atol(++str);

            while (*str != 0 && *str <= '9') str++;
            if (*str == 0) break;

            /* Copy DST name */
            strncpy(tz_dst_name, str, 3);

            // FIXME: set dst_begin etc

            /* We are finished */
            break;
        }

        _timezone = sign * (((hour * 60) + min) * 60 + sec);

    }
    else
    {
        TIME_ZONE_INFORMATION tzi;
        DWORD ret;

        ret = GetTimeZoneInformation(&tzi);
        if (ret == TIME_ZONE_ID_INVALID)
        {
            return;
        }

        ret = WideCharToMultiByte(CP_ACP,
                                  0,
                                  tzi.StandardName,
                                  -1,
                                  tz_name,
                                  sizeof(tz_name),
                                  NULL,
                                  NULL);

        ret = WideCharToMultiByte(CP_ACP,
                                  0,
                                  tzi.DaylightName,
                                  -1,
                                  tz_dst_name,
                                  sizeof(tz_dst_name),
                                  NULL,
                                  NULL);

        _timezone = tzi.Bias * 60;

        if (tzi.DaylightDate.wMonth)
        {
            struct tm _tm;

            _daylight = 1;
            _dstbias = (tzi.DaylightBias - tzi.StandardBias) * 60;
            _tm.tm_year = 70;
            _tm.tm_mon = tzi.DaylightDate.wMonth - 1;
            _tm.tm_mday = tzi.DaylightDate.wDay;
            _tm.tm_hour = tzi.DaylightDate.wHour;
            _tm.tm_min = tzi.DaylightDate.wMinute;
            _tm.tm_sec = tzi.DaylightDate.wSecond;
            dst_begin = (long)_mkgmtime(&_tm);
            _tm.tm_mon = tzi.StandardDate.wMonth - 1;
            _tm.tm_mday = tzi.StandardDate.wDay;
            _tm.tm_hour = tzi.StandardDate.wHour;
            _tm.tm_min = tzi.StandardDate.wMinute;
            _tm.tm_sec = tzi.StandardDate.wSecond;
            dst_end = (long)_mkgmtime(&_tm);
        }
        else
        {
            _daylight = 0;
            _dstbias = 0;
        }

    }
    _tz_is_set = 1;
}

/*********************************************************************
 *		_get_tzname (MSVCRT.@)
 */
int CDECL _get_tzname(size_t *ret, char *buf, size_t bufsize, int index)
{
    char *str_timezone;

    switch (index)
    {
    case 0:
        str_timezone = tz_name;
        break;

    case 1:
        str_timezone = tz_dst_name;
        break;

    default:
        *_errno() = EINVAL;
        return EINVAL;
    }

    if (!ret || (!buf && (bufsize > 0)) || (buf && !bufsize))
    {
        *_errno() = EINVAL;
        return EINVAL;
    }

    *ret = strlen(str_timezone) + 1;
    if(!buf && !bufsize)
        return 0;

    strncpy(buf, str_timezone, bufsize);
    return 0;
}