/*++

Copyright (c) 1994-2000,  Microsoft Corporation  All rights reserved.

Module Name:

    datedlg.c

Abstract:

    This module implements the date property sheet for the Regional
    Options applet.

Revision History:

--*/



//
//  Include Files.
//

#include "intl.h"
#include <windowsx.h>
#include <tchar.h>
#include <commctrl.h>
#include "intlhlp.h"
#include "maxvals.h"
#include "winnlsp.h"



//
//  Context Help Ids.
//

static int aDateHelpIds[] =
{
    IDC_GROUPBOX1,             IDH_COMM_GROUPBOX,
    IDC_GROUPBOX2,             IDH_COMM_GROUPBOX,
    IDC_GROUPBOX3,             IDH_COMM_GROUPBOX,
    IDC_SAMPLE1,               IDH_INTL_DATE_SHORTSAMPLE,
    IDC_SAMPLELBL1,            IDH_INTL_DATE_SHORTSAMPLE,
    IDC_SAMPLE1A,              IDH_INTL_DATE_SHORTSAMPLE_ARABIC,
    IDC_SAMPLELBL1A,           IDH_INTL_DATE_SHORTSAMPLE_ARABIC,
    IDC_SHORT_DATE_STYLE,      IDH_INTL_DATE_SHORTSTYLE,
    IDC_SEPARATOR,             IDH_INTL_DATE_SEPARATOR,
    IDC_SAMPLE2,               IDH_INTL_DATE_LONGSAMPLE,
    IDC_SAMPLELBL2,            IDH_INTL_DATE_LONGSAMPLE,
    IDC_SAMPLE2A,              IDH_INTL_DATE_LONGSAMPLE_ARABIC,
    IDC_SAMPLELBL2A,           IDH_INTL_DATE_LONGSAMPLE_ARABIC,
    IDC_LONG_DATE_STYLE,       IDH_INTL_DATE_LONGSTYLE,
    IDC_CALENDAR_TYPE_TEXT,    IDH_INTL_DATE_CALENDARTYPE,
    IDC_CALENDAR_TYPE,         IDH_INTL_DATE_CALENDARTYPE,
    IDC_TWO_DIGIT_YEAR_LOW,    IDH_INTL_DATE_TWO_DIGIT_YEAR,
    IDC_TWO_DIGIT_YEAR_HIGH,   IDH_INTL_DATE_TWO_DIGIT_YEAR,
    IDC_TWO_DIGIT_YEAR_ARROW,  IDH_INTL_DATE_TWO_DIGIT_YEAR,
    IDC_ADD_HIJRI_DATE,        IDH_INTL_DATE_ADD_HIJRI_DATE,
    IDC_ADD_HIJRI_DATE_TEXT,   IDH_INTL_DATE_ADD_HIJRI_DATE,

    0, 0
};



//
//  Global Variables.
//

TCHAR szNLS_LongDate[SIZE_128];
TCHAR szNLS_ShortDate[SIZE_128];

static TCHAR sz_iCalendarType[MAX_ICALTYPE + 1];
static TCHAR sz_sDate[MAX_SDATE + 1];
static TCHAR sz_sLongDate[MAX_SLONGDATE + 1];
static TCHAR sz_sShortDate[MAX_FORMAT + 1];


static const TCHAR c_szInternational[] = TEXT("Control Panel\\International");
static const TCHAR c_szAddHijriDate[]  = TEXT("AddHijriDate");
static const TCHAR c_szAddHijriDateTemp[] = TEXT("AddHijriDateTemp");
static const PTSTR c_szAddHijriDateValues[] =
{
  TEXT("AddHijriDate-2"),
  TEXT("AddHijriDate"),
  TEXT(""),
  TEXT("AddHijriDate+1"),
  TEXT("AddHijriDate+2")
};

static const TCHAR c_szTwoDigitYearKey[] = TEXT("Software\\Policies\\Microsoft\\Control Panel\\International\\Calendars\\TwoDigitYearMax");



//
//  Function Prototypes.
//

void Date_InitializeHijriDateComboBox(
    HWND hDlg);





////////////////////////////////////////////////////////////////////////////
//
//  Date_EnumerateDates
//
//  Enumerates the appropriate dates for the chosen calendar.
//
////////////////////////////////////////////////////////////////////////////

void Date_EnumerateDates(
    HWND hDlg,
    DWORD dwDateFlag)
{
    DWORD dwLocaleFlag;
    int nItemId;
    DWORD dwIndex;
    DWORD dwCalNum = 0;
    TCHAR szBuf[SIZE_128];
    HWND hCtrlDate;
    HWND hCtrlCal = GetDlgItem(hDlg, IDC_CALENDAR_TYPE);


    //
    //  Initialize variables according to the dwDateFlag parameter.
    //
    if (dwDateFlag == CAL_SSHORTDATE)
    {
        dwLocaleFlag = LOCALE_SSHORTDATE;
        nItemId = IDC_SHORT_DATE_STYLE;
    }
    else           // CAL_SLONGDATE
    {
        dwLocaleFlag = LOCALE_SLONGDATE;
        nItemId = IDC_LONG_DATE_STYLE;
    }
    hCtrlDate = GetDlgItem(hDlg, nItemId);

    //
    //  Initialize to reset the contents for the appropriate combo box.
    //
    if (!Set_List_Values(hDlg, nItemId, 0))
    {
        return;
    }

    //
    //  Reset the contents of the combo box.
    //
    ComboBox_ResetContent(hCtrlDate);

    //
    //  Get the currently selected calendar id.
    //
    dwIndex = ComboBox_GetCurSel(hCtrlCal);
    if (dwIndex != CB_ERR)
    {
        dwCalNum = (DWORD)ComboBox_GetItemData(hCtrlCal, dwIndex);
    }

    //
    //  Enumerate the dates for the currently selected calendar.
    //
    EnumCalendarInfo(EnumProc, UserLocaleID, dwCalNum, dwDateFlag);
    dwIndex = ComboBox_GetCount(hCtrlCal);
    if ((dwIndex == 0) || (dwIndex == CB_ERR))
    {
        EnumCalendarInfo(EnumProc, UserLocaleID, CAL_GREGORIAN, dwDateFlag);
    }

    //
    //  Add (if necesary) and select the current user setting in the
    //  combo box.
    //
    dwIndex = 0;
    if (GetLocaleInfo(UserLocaleID, dwLocaleFlag, szBuf, SIZE_128))
    {
        if ((dwIndex = ComboBox_FindStringExact(hCtrlDate, -1, szBuf)) == CB_ERR)
        {
            //
            //  Need to add this entry to the combo box.
            //
            Set_List_Values(0, 0, szBuf);
            if ((dwIndex = ComboBox_FindStringExact(hCtrlDate, -1, szBuf)) == CB_ERR)
            {
                dwIndex = 0;
            }
        }
    }
    else
    {
        MessageBox(hDlg, szLocaleGetError, NULL, MB_OK | MB_ICONINFORMATION);
    }
    Set_List_Values(0, nItemId, 0);

    Localize_Combobox_Styles(hDlg, nItemId, dwLocaleFlag);
    ComboBox_SetCurSel(hCtrlDate, dwIndex);
}


////////////////////////////////////////////////////////////////////////////
//
//  Date_GetTwoDigitYearRangeFromPolicy
//
//  Read the two digit year from the Policy registry.
//
////////////////////////////////////////////////////////////////////////////

BOOL Date_GetTwoDigitYearRangeFromPolicy(
    CALID CalId)
{
    HKEY hKey;
    BYTE buf[MAX_PATH];
    TCHAR szCalId[MAX_PATH];
    DWORD dwResultLen = sizeof(buf), dwType;
    BOOL bRet = FALSE;


    //
    //  Convert CalendarId to a string.
    //
    wsprintf(szCalId, TEXT("%d"), CalId);

    if (RegOpenKey( HKEY_CURRENT_USER,
                    c_szTwoDigitYearKey,
                    &hKey ) == ERROR_SUCCESS)
    {
        if ((RegQueryValueEx( hKey,
                              szCalId,
                              NULL,
                              &dwType,
                              &buf[0],
                              &dwResultLen ) == ERROR_SUCCESS) &&
            (dwType == REG_SZ) &&
            (dwResultLen > 2))
        {
            bRet = TRUE;
        }

        RegCloseKey(hKey);
    }

    //
    //  Return the result.
    //
    return (bRet);
}


////////////////////////////////////////////////////////////////////////////
//
//  Date_GetTwoDigitYearRange
//
//  Fills in the two digit year range controls.
//
////////////////////////////////////////////////////////////////////////////

void Date_GetTwoDigitYearRange(
    HWND hDlg,
    CALID CalId)
{
    HWND hwndYearHigh = GetDlgItem(hDlg, IDC_TWO_DIGIT_YEAR_HIGH);
    HWND hwndScroll = GetDlgItem(hDlg, IDC_TWO_DIGIT_YEAR_ARROW);
    DWORD YearHigh, YearHighDefault;

    //
    //  Enable the high range control.
    //
    EnableWindow(hwndYearHigh, TRUE);
    EnableWindow(hwndScroll, TRUE);

    //
    //  Get the default two digit year upper boundary.
    //
    if (!GetCalendarInfo( LOCALE_USER_DEFAULT,
                          CalId,
                          CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER |
                            CAL_NOUSEROVERRIDE,
                          NULL,
                          0,
                          &YearHighDefault ))
    {
        YearHighDefault = 0;
    }

    //
    //  Disable the two digit year upper boundary control if it is
    //  enforced by a policy or if the default value is 99 or less.
    //
    if ((Date_GetTwoDigitYearRangeFromPolicy(CalId)) ||
        (YearHighDefault <= 99))
    {
        //
        //  Disable the two digit year max controls.
        //
        EnableWindow(hwndScroll, FALSE);
        EnableWindow(hwndYearHigh, FALSE);
    }

    //
    //  Get the two digit year upper boundary.  If the default is less
    //  than or equal to 99, then use the default value and ignore the
    //  registry.  This is done for calendars like the Japanese Era
    //  calendar where it doesn't make sense to have a sliding window.
    //
    if (YearHighDefault <= 99)
    {
        YearHigh = YearHighDefault;
    }
    else if (!GetCalendarInfo( LOCALE_USER_DEFAULT,
                               CalId,
                               CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER,
                               NULL,
                               0,
                               &YearHigh ) ||
             (YearHigh < 99) || (YearHigh > 9999))
    {
        YearHigh = (YearHighDefault >= 99) ? YearHighDefault : 2029;
    }

    //
    //  Set the range on the controls.
    //
    SendMessage(hwndScroll, UDM_SETRANGE, 0, MAKELPARAM(9999, 99));
    SendMessage(hwndScroll, UDM_SETBUDDY, (WPARAM)hwndYearHigh, 0L);

    //
    //  Set the values of the controls.
    //
    SetDlgItemInt(hDlg, IDC_TWO_DIGIT_YEAR_LOW, (UINT)(YearHigh - 99), FALSE);
    SendMessage(hwndScroll, UDM_SETPOS, 0, MAKELONG((short)YearHigh, 0));
}


////////////////////////////////////////////////////////////////////////////
//
//  Date_SetTwoDigitYearMax
//
//  Sets the two digit year max value in the registry.
//
////////////////////////////////////////////////////////////////////////////

BOOL Date_SetTwoDigitYearMax(
    HWND hDlg,
    CALID CalId)
{
    TCHAR szYear[SIZE_64];

    //
    //  Get the max year.
    //
    szYear[0] = 0;
    if (GetWindowText( GetDlgItem(hDlg, IDC_TWO_DIGIT_YEAR_HIGH),
                       szYear,
                       SIZE_64 ) != 0)
    {
        //
        //  Set the two digit year upper boundary.
        //
        return (SetCalendarInfo( LOCALE_USER_DEFAULT,
                                 CalId,
                                 CAL_ITWODIGITYEARMAX,
                                 szYear ));
    }

    //
    //  Return success.
    //
    return (TRUE);
}


////////////////////////////////////////////////////////////////////////////
//
//  Date_ChangeYear
//
//  Changes the lower bound based on the upper bound value.
//
////////////////////////////////////////////////////////////////////////////

void Date_ChangeYear(
    HWND hDlg)
{
    DWORD YearHigh;
    BOOL bSuccess;

    //
    //  Get the two digit year upper boundary.
    //
    YearHigh = GetDlgItemInt(hDlg, IDC_TWO_DIGIT_YEAR_HIGH, &bSuccess, FALSE);

    if ((!bSuccess) || (YearHigh < 99) || (YearHigh > 9999))
    {
        //
        //  Invalid value, so set the lower control to 0.
        //
        SetDlgItemInt(hDlg, IDC_TWO_DIGIT_YEAR_LOW, 0, FALSE);
    }
    else
    {
        //
        //  Set the value of the lower control.
        //
        SetDlgItemInt(hDlg, IDC_TWO_DIGIT_YEAR_LOW, (UINT)(YearHigh - 99), FALSE);
    }
}


////////////////////////////////////////////////////////////////////////////
//
//  Date_DisplaySample
//
//  Updates the date samples.  It formats the date based on the user's
//  current locale settings.
//
////////////////////////////////////////////////////////////////////////////

void Date_DisplaySample(
    HWND hDlg)
{
    TCHAR szBuf[MAX_SAMPLE_SIZE];
    BOOL bNoError = TRUE;

    if (!bShowArabic) {
        // If user locale is not Arabic, make sure that the control for date samples are:
        //  * LTR reading orders for non-Hebrew locales
        //  * RTL reading orders for Hebrew locales.
        SetControlReadingOrder(bHebrewUI, GetDlgItem(hDlg, IDC_SAMPLE1));
        SetControlReadingOrder(bHebrewUI, GetDlgItem(hDlg, IDC_SAMPLE2));
    }

    // In Hebrew locale, we want to format the short date for left-to-right reading order.
    // If we make it right-to-left reading order, the Gregorian short date will display
    // in a complete different display order.  
    // The left-to-right reading order won't affect the Hebrew short date display.
    if (GetDateFormat( UserLocaleID,
                       (bHebrewUI ? DATE_LTRREADING :
                       (bShowRtL ? DATE_LTRREADING : 0)) | DATE_SHORTDATE,
                       NULL,
                       NULL,
                       szBuf,
                       MAX_SAMPLE_SIZE ))
    {
        SetDlgItemText(hDlg, IDC_SAMPLE1, szBuf);
    }
    else
    {
        MessageBox(hDlg, szLocaleGetError, NULL, MB_OK | MB_ICONINFORMATION);
        bNoError = FALSE;
    }

    //
    //  Show or hide the Arabic info based on the current user locale id.
    //
    ShowWindow(GetDlgItem(hDlg, IDC_SAMPLELBL1A), bShowArabic ? SW_SHOW : SW_HIDE);
    ShowWindow(GetDlgItem(hDlg, IDC_SAMPLE1A), bShowArabic ? SW_SHOW : SW_HIDE);
    if (bShowArabic)
    {
        if (GetDateFormat( UserLocaleID,
                           DATE_RTLREADING | DATE_SHORTDATE,
                           NULL,
                           NULL,
                           szBuf,
                           MAX_SAMPLE_SIZE ))
        {
            SetDlgItemText(hDlg, IDC_SAMPLE1A, szBuf);
            SetDlgItemRTL(hDlg, IDC_SAMPLE1A);
        }
        else
        {
            MessageBox(hDlg, szLocaleGetError, NULL, MB_OK | MB_ICONINFORMATION);
            bNoError = FALSE;
        }
    }

    if (GetDateFormat( UserLocaleID,
                       (bHebrewUI ? DATE_RTLREADING :
                         (bShowRtL ? DATE_LTRREADING : 0)) | DATE_LONGDATE,
                       NULL,
                       NULL,
                       szBuf,
                       MAX_SAMPLE_SIZE ))
    {
        SetDlgItemText(hDlg, IDC_SAMPLE2, szBuf);
    }
    else if (bNoError)
    {
        MessageBox(hDlg, szLocaleGetError, NULL, MB_OK | MB_ICONINFORMATION);
    }

    //
    //  Show or hide the Right to left info based on the current user locale id.
    //
    ShowWindow(GetDlgItem(hDlg, IDC_SAMPLELBL2A), bShowArabic ? SW_SHOW : SW_HIDE);
    ShowWindow(GetDlgItem(hDlg, IDC_SAMPLE2A), bShowArabic ? SW_SHOW : SW_HIDE);
    if (bShowArabic)
    {
        if (GetDateFormat( UserLocaleID,
                           DATE_RTLREADING | DATE_LONGDATE,
                           NULL,
                           NULL,
                           szBuf,
                           MAX_SAMPLE_SIZE ))
        {
            SetDlgItemText(hDlg, IDC_SAMPLE2A, szBuf);
            SetDlgItemRTL(hDlg, IDC_SAMPLE2A);
        }
        else if (bNoError)
        {
            MessageBox(hDlg, szLocaleGetError, NULL, MB_OK | MB_ICONINFORMATION);
        }
    }
}


////////////////////////////////////////////////////////////////////////////
//
//  Date_ClearValues
//
//  Reset each of the list boxes in the date property sheet page.
//
////////////////////////////////////////////////////////////////////////////

void Date_ClearValues(
    HWND hDlg)
{
    ComboBox_ResetContent(GetDlgItem(hDlg, IDC_SHORT_DATE_STYLE));
    ComboBox_ResetContent(GetDlgItem(hDlg, IDC_LONG_DATE_STYLE));
    ComboBox_ResetContent(GetDlgItem(hDlg, IDC_SEPARATOR));
    ComboBox_ResetContent(GetDlgItem(hDlg, IDC_CALENDAR_TYPE));
    ComboBox_ResetContent(GetDlgItem(hDlg, IDC_TWO_DIGIT_YEAR_LOW));
    ComboBox_ResetContent(GetDlgItem(hDlg, IDC_TWO_DIGIT_YEAR_HIGH));
}


////////////////////////////////////////////////////////////////////////////
//
//  Date_EnableHijriComboBox
//
//  Enables/Disables Show/Hides the Hijri date advance combo where necessary
//
////////////////////////////////////////////////////////////////////////////

void Date_EnableHijriComboBox(
    HWND hDlg,
    BOOL Status)
{
    HWND hAddHijriDateCB = GetDlgItem(hDlg, IDC_ADD_HIJRI_DATE);
    HWND hAddHijriDateText = GetDlgItem(hDlg, IDC_ADD_HIJRI_DATE_TEXT);
    INT iCount;

    //
    //  If the combo box is empty, then disable it.
    //
    iCount = (INT)SendMessage(hAddHijriDateCB, CB_GETCOUNT, 0L, 0L);
    if ((iCount == CB_ERR) || (iCount <= 0L))
    {
        Status = FALSE;
    }

    EnableWindow(hAddHijriDateCB, Status);
    ShowWindow(hAddHijriDateCB, Status ? SW_SHOW : SW_HIDE );

    EnableWindow(hAddHijriDateText, Status);
    ShowWindow(hAddHijriDateText, Status ? SW_SHOW : SW_HIDE);
}


////////////////////////////////////////////////////////////////////////////
//
//  Date_SaveValues
//
//  Save values in the case that we need to restore them.
//
////////////////////////////////////////////////////////////////////////////

void Date_SaveValues()
{
    //
    //  Save registry values.
    //
    if (!GetLocaleInfo( UserLocaleID,
                        LOCALE_ICALENDARTYPE,
                        sz_iCalendarType,
                        MAX_ICALTYPE + 1 ))
    {
        _tcscpy(sz_iCalendarType, TEXT("1"));
    }
    if (!GetLocaleInfo( UserLocaleID,
                        LOCALE_SDATE,
                        sz_sDate,
                        MAX_SDATE + 1 ))
    {
        _tcscpy(sz_sDate, TEXT("/"));
    }
    if (!GetLocaleInfo( UserLocaleID,
                        LOCALE_SLONGDATE,
                        sz_sLongDate,
                        MAX_SLONGDATE + 1 ))
    {
        _tcscpy(sz_sLongDate, TEXT("dddd, MMMM dd, yyyy"));
    }
    if (!GetLocaleInfo( UserLocaleID,
                        LOCALE_SSHORTDATE,
                        sz_sShortDate,
                        MAX_SSHORTDATE + 1 ))
    {
        _tcscpy(sz_sShortDate, TEXT("M/d/yyyy"));
    }
}


////////////////////////////////////////////////////////////////////////////
//
//  Date_RestoreValues
//
////////////////////////////////////////////////////////////////////////////

void Date_RestoreValues()
{
    if (g_dwCustChange & Process_Date)
    {
        SetLocaleInfo(UserLocaleID, LOCALE_ICALENDARTYPE, sz_iCalendarType);
        SetLocaleInfo(UserLocaleID, LOCALE_SDATE,         sz_sDate);
        SetLocaleInfo(UserLocaleID, LOCALE_SLONGDATE,     sz_sLongDate);
        SetLocaleInfo(UserLocaleID, LOCALE_SSHORTDATE,    sz_sShortDate);
    }
}


////////////////////////////////////////////////////////////////////////////
//
//  Date_SetValues
//
//  Initialize all of the controls in the date property sheet page.
//
////////////////////////////////////////////////////////////////////////////

void Date_SetValues(
    HWND hDlg)
{
    TCHAR szBuf[SIZE_128];
    int i, nItem;
    HWND hCtrl;
    LONG CalId;

    //
    //  Initialize the dropdown box for the current locale setting for the
    //  date separator.
    //
    DropDown_Use_Locale_Values(hDlg, LOCALE_SDATE, IDC_SEPARATOR);

    //
    //  Initialize and Lock function.  If it succeeds, call enum function to
    //  enumerate all possible values for the list box via a call to EnumProc.
    //  EnumProc will call Set_List_Values for each of the string values it
    //  receives.  When the enumeration of values is complete, call
    //  Set_List_Values to clear the dialog item specific data and to clear
    //  the lock on the function.  Perform this set of operations for:
    //  Calendar Type, Short Date Sytle, and Long Date Style.
    //
    if (Set_List_Values(hDlg, IDC_CALENDAR_TYPE, 0))
    {
        hCtrl = GetDlgItem(hDlg, IDC_CALENDAR_TYPE);
        EnumCalendarInfo(EnumProc, UserLocaleID, ENUM_ALL_CALENDARS, CAL_SCALNAME);
        Set_List_Values(0, IDC_CALENDAR_TYPE, 0);
        EnumCalendarInfo(EnumProc, UserLocaleID, ENUM_ALL_CALENDARS, CAL_ICALINTVALUE);
        Set_List_Values(0, IDC_CALENDAR_TYPE, 0);
        if (GetLocaleInfo(UserLocaleID, LOCALE_ICALENDARTYPE, szBuf, SIZE_128))
        {
            TCHAR szBufTmp[SIZE_128] = {0};
            int iTmp = 0;
            LONG CalIdTmp;

            if( GetLocaleInfo( UserLocaleID,
                               LOCALE_ICALENDARTYPE | LOCALE_NOUSEROVERRIDE,
                               szBufTmp,
                               SIZE_128))
            {
                //
                //  Convert the id to a number.
                //
                CalId = Intl_StrToLong(szBuf);
                CalIdTmp = Intl_StrToLong(szBufTmp);

                //
                //  Search for calendars
                //
                nItem = ComboBox_GetCount(hCtrl);
                for (i = 0; i < nItem; i++)
                {
                    if (ComboBox_GetItemData(hCtrl, i) == CalId)
                    {
                        break;
                    }

                    if (ComboBox_GetItemData(hCtrl, i) == CalIdTmp)
                    {
                        iTmp = i;
                    }
                }

                //
                //  Look if we find something.
                //
                if (i < nItem)
                {
                    ComboBox_SetCurSel(hCtrl, i);
                }
                else
                {
                    CalId = CalIdTmp;
                    ComboBox_SetCurSel(hCtrl, iTmp);  // Zero or something else.
                }

                //
                //  Enable/disable the Add Hijri date check box.
                //
                Date_InitializeHijriDateComboBox(hDlg);
                Date_EnableHijriComboBox(hDlg, (CalId == CAL_HIJRI));

                //
                //  Set the two digit year range.
                //
                Date_GetTwoDigitYearRange(hDlg, (CALID)CalId);

                //
                //  Subtract 1 from calendar value because calendars are one
                //  based, not zero based like all other locale values.
                //
            }
        }
        else
        {
            MessageBox(hDlg, szLocaleGetError, NULL, MB_OK | MB_ICONINFORMATION);
        }

        //
        //  If more than one selection, enable dropdown box.
        //  Otherwise, disable it.
        //
        if (ComboBox_GetCount(hCtrl) > 1)
        {
            EnableWindow(GetDlgItem(hDlg, IDC_CALENDAR_TYPE_TEXT), TRUE);
            EnableWindow(GetDlgItem(hDlg, IDC_CALENDAR_TYPE), TRUE);
            ShowWindow(GetDlgItem(hDlg, IDC_CALENDAR_TYPE_TEXT), SW_SHOW);
            ShowWindow(GetDlgItem(hDlg, IDC_CALENDAR_TYPE), SW_SHOW);
        }
        else
        {
            EnableWindow(GetDlgItem(hDlg, IDC_CALENDAR_TYPE_TEXT), FALSE);
            EnableWindow(GetDlgItem(hDlg, IDC_CALENDAR_TYPE), FALSE);
            ShowWindow(GetDlgItem(hDlg, IDC_CALENDAR_TYPE_TEXT), SW_HIDE);
            ShowWindow(GetDlgItem(hDlg, IDC_CALENDAR_TYPE), SW_HIDE);
        }
    }
    Date_EnumerateDates(hDlg, CAL_SSHORTDATE);
    Date_EnumerateDates(hDlg, CAL_SLONGDATE);

    //
    //  Display the current sample that represents all of the locale settings.
    //
    Date_DisplaySample(hDlg);
}


////////////////////////////////////////////////////////////////////////////
//
//  Date_SetHijriDate
//
//  Saves the Hijri date advance amount to the registry.
//
////////////////////////////////////////////////////////////////////////////

void Date_SetHijriDate(
    HWND hHijriComboBox)
{
    HKEY hKey;
    INT iIndex;

    //
    //  Get the string index to set.
    //
    iIndex = (INT)SendMessage(hHijriComboBox, CB_GETCURSEL, 0L, 0L);

    if (iIndex == CB_ERR)
    {
        return;
    }

    iIndex = (INT)SendMessage(hHijriComboBox, CB_GETITEMDATA, (WPARAM)iIndex, 0L);
    if (iIndex != CB_ERR)
    {
        if (RegOpenKeyEx( HKEY_CURRENT_USER,
                          c_szInternational,
                          0,
                          KEY_READ | KEY_WRITE,
                          &hKey ) == ERROR_SUCCESS)
        {
            RegSetValueEx( hKey,
                           c_szAddHijriDate,
                           0,
                           REG_SZ,
                           (LPBYTE)c_szAddHijriDateValues[iIndex],
                           (lstrlen(c_szAddHijriDateValues[iIndex]) + 1) * sizeof(TCHAR) );

            RegCloseKey(hKey);
        }
    }
}


////////////////////////////////////////////////////////////////////////////
//
//  Date_ApplySettings
//
//  For every control that has changed (that affects the Locale settings),
//  call Set_Locale_Values to update the user locale information.  Notify
//  the parent of changes and reset the change flag stored in the property
//  sheet page structure appropriately.  Redisplay the date sample if
//  bRedisplay is TRUE.
//
////////////////////////////////////////////////////////////////////////////

BOOL Date_ApplySettings(
    HWND hDlg,
    BOOL bRedisplay)
{
    TCHAR szBuf[SIZE_128];
    CALID CalId = 0;
    LPPROPSHEETPAGE lpPropSheet = (LPPROPSHEETPAGE)(GetWindowLongPtr(hDlg, DWLP_USER));
    LPARAM Changes = lpPropSheet->lParam;
    HWND hwndYearHigh = GetDlgItem(hDlg, IDC_TWO_DIGIT_YEAR_HIGH);

    if (Changes & DC_ShortFmt)
    {
        //
        //  szNLS_ShortDate is set in Date_ValidatePPS.
        //
        if (!Set_Locale_Values( hDlg,
                                LOCALE_SSHORTDATE,
                                IDC_SHORT_DATE_STYLE,
                                TEXT("sShortDate"),
                                FALSE,
                                0,
                                0,
                                szNLS_ShortDate ))
        {
            return (FALSE);
        }

        //
        //  If the date separator field has also been changed by the user,
        //  then don't update now.  It will be updated below.
        //
        if (!(Changes & DC_SDate))
        {
            //
            //  Since the short date style changed, reset date separator
            //  list box.
            //
            ComboBox_ResetContent(GetDlgItem(hDlg, IDC_SEPARATOR));
            DropDown_Use_Locale_Values(hDlg, LOCALE_SDATE, IDC_SEPARATOR);
            if (!Set_Locale_Values( hDlg,
                                    LOCALE_SDATE,
                                    IDC_SEPARATOR,
                                    TEXT("sDate"),
                                    FALSE,
                                    0,
                                    0,
                                    NULL ))
            {
                return (FALSE);
            }
        }
    }
    if (Changes & DC_LongFmt)
    {
        //
        //  szNLS_LongDate is set in Date_ValidatePPS.
        //
        if (!Set_Locale_Values( hDlg,
                                LOCALE_SLONGDATE,
                                IDC_LONG_DATE_STYLE,
                                TEXT("sLongDate"),
                                FALSE,
                                0,
                                0,
                                szNLS_LongDate ))
        {
            return (FALSE);
        }
    }
    if (Changes & DC_SDate)
    {
        if (!Set_Locale_Values( hDlg,
                                LOCALE_SDATE,
                                IDC_SEPARATOR,
                                TEXT("sDate"),
                                FALSE,
                                0,
                                0,
                                NULL ))
        {
            return (FALSE);
        }

        //
        //  Since the date separator changed, reset the short date style
        //  list box.
        //
        Date_EnumerateDates(hDlg, CAL_SSHORTDATE);
    }
    if (Changes & DC_Calendar)
    {
        if (!Set_Locale_Values( hDlg,
                                LOCALE_ICALENDARTYPE,
                                IDC_CALENDAR_TYPE,
                                0,
                                TRUE,
                                1,
                                0,
                                NULL ))
        {
            return (FALSE);
        }

        if (GetLocaleInfo(UserLocaleID, LOCALE_ICALENDARTYPE, szBuf, SIZE_128))
        {
            CalId = Intl_StrToLong(szBuf);
            Date_InitializeHijriDateComboBox(hDlg);
            Date_EnableHijriComboBox(hDlg, (CalId == CAL_HIJRI));
        }
    }

    if (Changes & DC_Arabic_Calendar)
    {
        Date_SetHijriDate( GetDlgItem(hDlg, IDC_ADD_HIJRI_DATE) );
    }

    if (Changes & DC_TwoDigitYearMax)
    {
        if (CalId == 0)
        {
            HWND hCtrl = GetDlgItem(hDlg, IDC_CALENDAR_TYPE);
            int index;

            if ((index = ComboBox_GetCurSel(hCtrl)) == CB_ERR)
            {
                if (GetLocaleInfo( UserLocaleID,
                                   LOCALE_ICALENDARTYPE | LOCALE_NOUSEROVERRIDE,
                                   szBuf,
                                   SIZE_128))
                {
                    CalId = Intl_StrToLong(szBuf);
                }
                else
                {
                    return (FALSE);
                }
            }
            else
            {
                CalId = (CALID)ComboBox_GetItemData(hCtrl, index);
            }
        }
        if (!Date_SetTwoDigitYearMax(hDlg, CalId))
        {
            //
            //  Make sure that the API failed due to a reason other than
            //  the upper year two digit max is <= 99. This can easily
            //  be checked by seeing if the control is enabled or not.
            //
            if (IsWindowEnabled(hwndYearHigh))
            {
                return (FALSE);
            }
        }
    }

    PropSheet_UnChanged(GetParent(hDlg), hDlg);
    lpPropSheet->lParam = DC_EverChg;

    //
    //  Display the current sample that represents all of the locale settings.
    //
    if (bRedisplay)
    {
        Date_DisplaySample(hDlg);
    }

    //
    //  Changes made in the second level.
    //
    if (Changes)
    {
        g_dwCustChange |= Process_Date;
    }

    //
    //  Return success.
    //
    return (TRUE);
}


////////////////////////////////////////////////////////////////////////////
//
//  Date_ValidatePPS
//
//  Validate each of the combo boxes whose values are constrained.
//  If any of the input fails, notify the user and then return FALSE
//  to indicate validation failure.
//
////////////////////////////////////////////////////////////////////////////

BOOL Date_ValidatePPS(
    HWND hDlg,
    LPARAM Changes)
{
    //
    //  If nothing has changed, return TRUE immediately.
    //
    if (Changes <= DC_EverChg)
    {
        return (TRUE);
    }

    //
    //  If the date separator has changed, ensure that there are no digits
    //  and no invalid characters contained in the new separator.
    //
    if (Changes & DC_SDate &&
        Item_Has_Digits_Or_Invalid_Chars( hDlg,
                                          IDC_SEPARATOR,
                                          FALSE,
                                          szInvalidSDate ))
    {
        No_Numerals_Error(hDlg, IDC_SEPARATOR, IDS_LOCALE_DATE_SEP);
        return (FALSE);
    }

    //
    //  If the short date style has changed, ensure that there are only
    //  characters in this set " dHhMmsty,-./:;\", the separator string,
    //  and text enclosed in single quotes.
    //
    if (Changes & DC_ShortFmt)
    {
        if (NLSize_Style( hDlg,
                          IDC_SHORT_DATE_STYLE,
                          szNLS_ShortDate,
                          LOCALE_SSHORTDATE ) ||
            Item_Check_Invalid_Chars( hDlg,
                                      szNLS_ShortDate,
                                      szSDateChars,
                                      IDC_SEPARATOR,
                                      FALSE,
                                      szSDCaseSwap,
                                      IDC_SHORT_DATE_STYLE ))
        {
            Invalid_Chars_Error(hDlg, IDC_SHORT_DATE_STYLE, IDS_LOCALE_SDATE);
            return (FALSE);
        }
    }

    //
    //  If the long date style has changed, ensure that there are only
    //  characters in this set " dgHhMmsty,-./:;\", the separator string,
    //  and text enclosed in single quotes.
    //
    if (Changes & DC_LongFmt)
    {
        if (NLSize_Style( hDlg,
                          IDC_LONG_DATE_STYLE,
                          szNLS_LongDate,
                          LOCALE_SLONGDATE ) ||
            Item_Check_Invalid_Chars( hDlg,
                                      szNLS_LongDate,
                                      szLDateChars,
                                      IDC_SEPARATOR,
                                      FALSE,
                                      szLDCaseSwap,
                                      IDC_LONG_DATE_STYLE ))
        {
            Invalid_Chars_Error(hDlg, IDC_LONG_DATE_STYLE, IDS_LOCALE_LDATE);
            return (FALSE);
        }
    }

    //
    //  If the two digit year has changed, make sure the value is between
    //  99 and 9999 (if the window is still enabled).
    //
    if (Changes & DC_TwoDigitYearMax)
    {
        DWORD YearHigh;
        BOOL bSuccess;

        if (IsWindowEnabled(GetDlgItem(hDlg, IDC_TWO_DIGIT_YEAR_HIGH)))
        {
            YearHigh = GetDlgItemInt( hDlg,
                                      IDC_TWO_DIGIT_YEAR_HIGH,
                                      &bSuccess,
                                      FALSE );

            if ((!bSuccess) || (YearHigh < 99) || (YearHigh > 9999))
            {
                TCHAR szBuf[SIZE_128];

                LoadString(hInstance, IDS_LOCALE_YEAR_ERROR, szBuf, SIZE_128);
                MessageBox(hDlg, szBuf, NULL, MB_OK | MB_ICONINFORMATION);
                SetFocus(GetDlgItem(hDlg, IDC_TWO_DIGIT_YEAR_HIGH));
                return (FALSE);
            }
        }
    }

    //
    //  Return success.
    //
    return (TRUE);
}


////////////////////////////////////////////////////////////////////////////
//
//  Date_InitializeHijriDateComboBox
//
//  Initialize the HijriDate advance combo box.
//
////////////////////////////////////////////////////////////////////////////

void Date_InitializeHijriDateComboBox(
    HWND hDlg)
{
    HWND hHijriDate = GetDlgItem(hDlg, IDC_ADD_HIJRI_DATE);
    HKEY hKey;
    TCHAR szBuf[128];
    TCHAR szCurrentValue[16];   // Max size ever needed should be 15 characters including the NULL
    INT iIndex;
    DWORD dwCtr, dwNumEntries, DataLen;


    //
    //  Clear contents.
    //
    SendMessage( hHijriDate,
                 CB_RESETCONTENT,
                 0L,
                 0L);

    if (RegOpenKeyEx( HKEY_CURRENT_USER,
                      c_szInternational,
                      0,
                      KEY_READ | KEY_WRITE,
                      &hKey ) == ERROR_SUCCESS)
    {
        //
        //  Read the default/current value.
        //

        // Use the byte count, the API expects that even for Unicode strings
        DataLen = sizeof(szCurrentValue);

        if (RegQueryValueEx( hKey,
                             c_szAddHijriDate,
                             NULL,
                             NULL,
                             (LPBYTE)szCurrentValue,
                             &DataLen ) != ERROR_SUCCESS)
        {
            szCurrentValue[0] = TEXT('\0');
        }

        dwNumEntries = (ARRAYSIZE(c_szAddHijriDateValues));
        for (dwCtr = 0; dwCtr < dwNumEntries; dwCtr++)
        {
            //
            //  Fill the combo box.
            //
            if (RegSetValueEx( hKey,
                               c_szAddHijriDateTemp,
                               0,
                               REG_SZ,
                               (LPBYTE)c_szAddHijriDateValues[dwCtr],
                               (lstrlen(c_szAddHijriDateValues[dwCtr]) + 1) * sizeof(TCHAR)) == ERROR_SUCCESS)
            {
                //
                //  0x80000000 is a private flag to make GetDateFormat read
                //  the HijriDate setting from the temp reg value.
                //
                if (GetDateFormat( MAKELCID(MAKELANGID(LANG_ARABIC,
                                                       SUBLANG_DEFAULT),
                                            SORT_DEFAULT),
                                   DATE_ADDHIJRIDATETEMP | DATE_LONGDATE |
                                     DATE_RTLREADING,
                                   NULL,
                                   NULL,
                                   szBuf,
                                   ARRAYSIZE(szBuf)))
                {
                    iIndex = (INT)SendMessage(hHijriDate, CB_ADDSTRING, 0L, (LPARAM)szBuf);
                    if (iIndex != CB_ERR)
                    {
                        SendMessage(hHijriDate, CB_SETITEMDATA, iIndex, (LPARAM)dwCtr);

                        if (!lstrcmp(szCurrentValue, c_szAddHijriDateValues[dwCtr]))
                        {
                            SendMessage(hHijriDate, CB_SETCURSEL, iIndex, 0L);
                        }
                    }
                }
            }
        }

        //
        //  Delete the value after we're done.
        //
        RegDeleteValue(hKey, c_szAddHijriDateTemp);

        RegCloseKey(hKey);
    }
}


////////////////////////////////////////////////////////////////////////////
//
//  Date_InitPropSheet
//
//  The extra long value for the property sheet page is used as a set of
//  state or change flags for each of the list boxes in the property sheet.
//  Initialize this value to 0.  Call Date_SetValues with the property
//  sheet handle and the value TRUE (to indicate that the Positive Value
//  button should also be initialized) to initialize all of the property
//  sheet controls.
//
////////////////////////////////////////////////////////////////////////////

void Date_InitPropSheet(
    HWND hDlg,
    LPARAM lParam)
{
    //
    //  The lParam holds a pointer to the property sheet page, save it
    //  for later reference.
    //
    SetWindowLongPtr(hDlg, DWLP_USER, lParam);

    //
    //  Set the values.
    //
    Date_SetValues(hDlg);
    szNLS_ShortDate[0] = szNLS_LongDate[0] = 0;

    ComboBox_LimitText(GetDlgItem(hDlg, IDC_SEPARATOR),        MAX_SDATE);
    ComboBox_LimitText(GetDlgItem(hDlg, IDC_SHORT_DATE_STYLE), MAX_FORMAT);
    ComboBox_LimitText(GetDlgItem(hDlg, IDC_LONG_DATE_STYLE),  MAX_FORMAT);

    Edit_LimitText(GetDlgItem(hDlg, IDC_TWO_DIGIT_YEAR_LOW),   MAX_YEAR);
    Edit_LimitText(GetDlgItem(hDlg, IDC_TWO_DIGIT_YEAR_HIGH),  MAX_YEAR);

    //
    //  Set the Add Hijri Date combo box appropriately.
    //
    if (bShowArabic)
    {
        Date_InitializeHijriDateComboBox(hDlg);
    }

    //
    //  Make sure the Apply button is off.
    //
    PropSheet_UnChanged(GetParent(hDlg), hDlg);
    if (lParam)
    {
        ((LPPROPSHEETPAGE)lParam)->lParam = DC_EverChg;
    }
}


////////////////////////////////////////////////////////////////////////////
//
//  DateDlgProc
//
////////////////////////////////////////////////////////////////////////////

INT_PTR CALLBACK DateDlgProc(
    HWND hDlg,
    UINT message,
    WPARAM wParam,
    LPARAM lParam)
{
    NMHDR *lpnm;
    LPPROPSHEETPAGE lpPropSheet = (LPPROPSHEETPAGE)(GetWindowLongPtr(hDlg, DWLP_USER));
    DWORD dwIndex;
    HWND hCtrl;

    switch (message)
    {
        case ( WM_INITDIALOG ) :
        {
            Date_InitPropSheet(hDlg, lParam);
            Date_SaveValues();
            break;
        }
        case ( WM_DESTROY ) :
        {
            break;
        }
        case ( WM_HELP ) :
        {
            WinHelp( (HWND)((LPHELPINFO)lParam)->hItemHandle,
                     szHelpFile,
                     HELP_WM_HELP,
                     (DWORD_PTR)(LPTSTR)aDateHelpIds );
            break;
        }
        case ( WM_CONTEXTMENU ) :      // right mouse click
        {
            WinHelp( (HWND)wParam,
                     szHelpFile,
                     HELP_CONTEXTMENU,
                     (DWORD_PTR)(LPTSTR)aDateHelpIds );
            break;
        }
        case ( WM_COMMAND ) :
        {
            if (!lpPropSheet)
            {
                break;
            }

            switch ( LOWORD(wParam) )
            {
                case ( IDC_SHORT_DATE_STYLE ) :
                {
                    if (HIWORD(wParam) == CBN_SELCHANGE ||
                        HIWORD(wParam) == CBN_EDITCHANGE)
                    {
                        lpPropSheet->lParam |= DC_ShortFmt;
                    }
                    break;
                }
                case ( IDC_LONG_DATE_STYLE ) :
                {
                    if (HIWORD(wParam) == CBN_SELCHANGE ||
                        HIWORD(wParam) == CBN_EDITCHANGE)
                    {
                        lpPropSheet->lParam |= DC_LongFmt;
                    }
                    break;
                }
                case ( IDC_SEPARATOR ) :
                {
                    if (HIWORD(wParam) == CBN_SELCHANGE ||
                        HIWORD(wParam) == CBN_EDITCHANGE)
                    {
                        lpPropSheet->lParam |= DC_SDate;
                    }
                    break;
                }
                case ( IDC_CALENDAR_TYPE ) :
                {
                    if (HIWORD(wParam) == CBN_SELCHANGE)
                    {
                        lpPropSheet->lParam |= DC_Calendar;

                        hCtrl = GetDlgItem(hDlg, IDC_CALENDAR_TYPE);
                        dwIndex = ComboBox_GetCurSel(hCtrl);
                        if (dwIndex != CB_ERR)
                        {
                            dwIndex = (DWORD)ComboBox_GetItemData(hCtrl, dwIndex);
                            Date_InitializeHijriDateComboBox(hDlg);
                            Date_EnableHijriComboBox(hDlg, (dwIndex == CAL_HIJRI) );
                            Date_GetTwoDigitYearRange(hDlg, (CALID)dwIndex);
                        }

                        Date_EnumerateDates(hDlg, CAL_SSHORTDATE);
                        Date_EnumerateDates(hDlg, CAL_SLONGDATE);
                    }
                    break;
                }
                case ( IDC_ADD_HIJRI_DATE ) :
                {
                    if (HIWORD(wParam) == CBN_SELCHANGE)
                    {
                        lpPropSheet->lParam |= DC_Arabic_Calendar;
                    }
                    break;
                }
                case ( IDC_TWO_DIGIT_YEAR_HIGH ) :
                {
                    if (GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE)
                    {
                        Date_ChangeYear(hDlg);
                        lpPropSheet->lParam |= DC_TwoDigitYearMax;
                    }
                    break;
                }
            }

            //
            //  Turn on ApplyNow button.
            //
            if (lpPropSheet->lParam > DC_EverChg)
            {
                PropSheet_Changed(GetParent(hDlg), hDlg);
            }

            break;
        }
        case ( WM_NOTIFY ) :
        {
            lpnm = (NMHDR *)lParam;
            switch (lpnm->code)
            {
                case ( PSN_SETACTIVE ) :
                {
                    //
                    //  If there has been a change in the regional Locale
                    //  setting, clear all of the current info in the
                    //  property sheet, get the new values, and update the
                    //  appropriate registry values.
                    //
                    if (Verified_Regional_Chg & Process_Date)
                    {
                        Verified_Regional_Chg &= ~Process_Date;
                        Date_ClearValues(hDlg);
                        Date_SetValues(hDlg);
                        lpPropSheet->lParam = 0;
                    }
                    break;
                }
                case ( PSN_KILLACTIVE ) :
                {
                    //
                    //  Validate the entries on the property page.
                    //
                    SetWindowLongPtr( hDlg,
                                   DWLP_MSGRESULT,
                                   !Date_ValidatePPS( hDlg,
                                                      lpPropSheet->lParam ) );
                    break;
                }
                case ( PSN_APPLY ) :
                {
                    //
                    //  Apply the settings.
                    //
                    if (Date_ApplySettings(hDlg, TRUE))
                    {
                        SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);

                        //
                        //  Zero out the DC_EverChg bit.
                        //
                        lpPropSheet->lParam = 0;
                    }
                    else
                    {
                        SetWindowLongPtr( hDlg,
                                       DWLP_MSGRESULT,
                                       PSNRET_INVALID_NOCHANGEPAGE );
                    }

                    break;
                }
                default :
                {
                    return (FALSE);
                }
            }
            break;
        }
        case ( WM_VSCROLL ) :
        {
            if ((GET_WM_VSCROLL_CODE(wParam, lParam) == SB_ENDSCROLL) &&
                ((HWND)SendMessage( GET_WM_VSCROLL_HWND(wParam, lParam),
                                   UDM_GETBUDDY,
                                   0,
                                   0L ) == GetDlgItem(hDlg, IDC_TWO_DIGIT_YEAR_HIGH)))
            {
                DWORD YearHigh;

                //
                //  Get the high year.
                //
                YearHigh = (DWORD)SendDlgItemMessage( hDlg,
                                                      IDC_TWO_DIGIT_YEAR_ARROW,
                                                      UDM_GETPOS,
                                                      0,
                                                      0L );

                //
                //  Set the low year based on the high year.
                //
                SetDlgItemInt( hDlg,
                               IDC_TWO_DIGIT_YEAR_LOW,
                               (UINT)(YearHigh - 99),
                               FALSE );

                //
                //  Mark it as changed.
                //
                lpPropSheet->lParam |= DC_TwoDigitYearMax;

                //
                //  Turn on ApplyNow button.
                //
                PropSheet_Changed(GetParent(hDlg), hDlg);
            }

            break;
        }
        default :
        {
            return (FALSE);
        }
    }

    //
    //  Return success.
    //
    return (TRUE);
}
