/////////////////////////////////////////////////////////////////////////////
//
//	Copyright (c) 1996-1997 Microsoft Corporation
//
//	Module Name:
//		DDxDDv.cpp
//
//	Abstract:
//		Implementation of custom dialog data exchange/dialog data validation
//		routines.
//
//	Author:
//		David Potter (davidp)	September 5, 1996
//
//	Revision History:
//
//	Notes:
//
/////////////////////////////////////////////////////////////////////////////

#include <afxwin.h>
#include <resapi.h>
#include "DDxDDv.h"
#include "AdmCommonRes.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// Static Function Prototypes
/////////////////////////////////////////////////////////////////////////////
void CleanupLabel(LPTSTR psz);

/////////////////////////////////////////////////////////////////////////////
//++
//
//	DDX_Number
//
//	Routine Description:
//		Do data exchange between the dialog and the class.
//
//	Arguments:
//		pDX			[IN OUT] Data exchange object 
//		nIDC		[IN] Control ID.
//		dwValue		[IN OUT] Value to set or get.
//		dwMin		[IN] Minimum value.
//		dwMax		[IN] Maximum value.
//		bSigned		[IN] TRUE = value is signed, FALSE = value is unsigned
//
//	Return Value:
//		None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void AFXAPI DDX_Number(
	IN OUT CDataExchange *	pDX,
	IN int					nIDC,
	IN OUT DWORD &			rdwValue,
	IN DWORD				dwMin,
	IN DWORD				dwMax,
	IN BOOL					bSigned
	)
{
	HWND	hwndCtrl;
	DWORD	dwValue;

	ASSERT(pDX != NULL);
#ifdef _DEBUG
	if (bSigned)
	{
		ASSERT((LONG) dwMin < (LONG) dwMax);
	}
	else
	{
		ASSERT(dwMin < dwMax);
	}
#endif // _DEBUG

	// Get the control window handle.
	hwndCtrl = pDX->PrepareEditCtrl(nIDC);

	if (pDX->m_bSaveAndValidate)
	{
		BOOL	bTranslated;

		// Get the number from the control.
		dwValue = GetDlgItemInt(pDX->m_pDlgWnd->m_hWnd, nIDC, &bTranslated, bSigned);

		// If the retrival failed, it is a signed number, and the minimum
		// value is the smallest negative value possible, check the string itself.
		if (!bTranslated && bSigned && (dwMin == 0x80000000))
		{
			UINT	cch;
			TCHAR	szNumber[20];

			// See if it is the smallest negative number.
			cch = GetDlgItemText(pDX->m_pDlgWnd->m_hWnd, nIDC, szNumber, sizeof(szNumber) / sizeof(TCHAR));
			if ((cch != 0) && (lstrcmp(szNumber, _T("-2147483648")) == 0))
			{
				dwValue = 0x80000000;
				bTranslated = TRUE;
			}  // if:  text retrieved successfully and is highest negative number
		}  // if:  error translating number and getting signed number

		// If the retrieval failed or the specified number is
		// out of range, display an error.
		if (   !bTranslated
			|| (bSigned && (((LONG) dwValue < (LONG) dwMin) || ((LONG) dwValue > (LONG) dwMax)))
			|| (!bSigned && ((dwValue < dwMin) || (dwValue > dwMax)))
			)
		{
			TCHAR szMin[32];
			TCHAR szMax[32];
			CString strPrompt;

			if (bSigned)
			{
				wsprintf(szMin, _T("%d%"), dwMin);
				wsprintf(szMax, _T("%d%"), dwMax);
			}  // if:  signed number
			else
			{
				wsprintf(szMin, _T("%u%"), dwMin);
				wsprintf(szMax, _T("%u%"), dwMax);
			}  // else:  unsigned number
			AfxFormatString2(strPrompt, AFX_IDP_PARSE_INT_RANGE, szMin, szMax);
			AfxMessageBox(strPrompt, MB_ICONEXCLAMATION, AFX_IDP_PARSE_INT_RANGE);
			strPrompt.Empty(); // exception prep
			pDX->Fail();
		}  // if:  invalid string
		else
			rdwValue = dwValue;
	}  // if:  saving data
	else
	{
		CString		strMinValue;
		CString		strMaxValue;
		UINT		cchMax;

		// Set the maximum number of characters that can be entered.
		if (bSigned)
		{
			strMinValue.Format(_T("%d"), dwMin);
			strMaxValue.Format(_T("%d"), dwMax);
		}  // if:  signed value
		else
		{
			strMinValue.Format(_T("%u"), dwMin);
			strMaxValue.Format(_T("%u"), dwMax);
		}  // else:  unsigned value
		cchMax = max(strMinValue.GetLength(), strMaxValue.GetLength());
		SendMessage(hwndCtrl, EM_LIMITTEXT, cchMax, 0);

		// Set the value into the control.
		if (bSigned)
		{
			LONG lValue = (LONG) rdwValue;
			DDX_Text(pDX, nIDC, lValue);
		}  // if:  signed value
		else
			DDX_Text(pDX, nIDC, rdwValue);
	}  // else:  setting data onto the dialog

}  //*** DDX_Number()

/////////////////////////////////////////////////////////////////////////////
//++
//
//	DDV_RequiredText
//
//	Routine Description:
//		Validate that the dialog string is present.
//
//	Arguments:
//		pDX			[IN OUT] Data exchange object 
//		nIDC		[IN] Control ID.
//		nIDCLabel	[IN] Label control ID.
//		rstrValue	[IN] Value to set or get.
//
//	Return Value:
//		None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void AFXAPI DDV_RequiredText(
	IN OUT CDataExchange *	pDX,
	IN int					nIDC,
	IN int					nIDCLabel,
	IN const CString &		rstrValue
	)
{
	ASSERT(pDX != NULL);

	if (pDX->m_bSaveAndValidate)
	{
		if (rstrValue.GetLength() == 0)
		{
			HWND		hwndLabel;
			TCHAR		szLabel[1024];
			CString		strPrompt;

			// Get the label window handle
			hwndLabel = pDX->PrepareEditCtrl(nIDCLabel);

			// Get the text of the label.
			GetWindowText(hwndLabel, szLabel, sizeof(szLabel) / sizeof(TCHAR));

			// Remove ampersands (&) and colons (:).
			CleanupLabel(szLabel);

			// Format and display a message.
			strPrompt.FormatMessage(ADMC_IDS_REQUIRED_FIELD_EMPTY, szLabel);
			AfxMessageBox(strPrompt, MB_ICONEXCLAMATION);

			// Do this so that the control receives focus.
			(void) pDX->PrepareEditCtrl(nIDC);

			// Fail the call.
			strPrompt.Empty();	// exception prep
			pDX->Fail();
		}  // if:  field not specified
	}  // if:  saving data

}  //*** DDV_RequiredText()

/////////////////////////////////////////////////////////////////////////////
//++
//
//	DDV_Path
//
//	Routine Description:
//		Validate that the path string contains valid characters.
//
//	Arguments:
//		pDX			[IN OUT] Data exchange object 
//		nIDC		[IN] Control ID.
//		nIDCLabel	[IN] Label control ID.
//		rstrValue	[IN] Path to validate.
//
//	Return Value:
//		None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void AFXAPI DDV_Path(
	IN OUT CDataExchange *	pDX,
	IN int					nIDC,
	IN int					nIDCLabel,
	IN const CString &		rstrValue
	)
{
	ASSERT(pDX != NULL);

	if (pDX->m_bSaveAndValidate)
	{
		if (!ResUtilIsPathValid(rstrValue))
		{
			HWND		hwndLabel;
			TCHAR		szLabel[1024];
			CString		strPrompt;

			// Get the label window handle
			hwndLabel = pDX->PrepareEditCtrl(nIDCLabel);

			// Get the text of the label.
			GetWindowText(hwndLabel, szLabel, sizeof(szLabel) / sizeof(TCHAR));

			// Remove ampersands (&) and colons (:).
			CleanupLabel(szLabel);

			// Format and display a message.
			strPrompt.FormatMessage(ADMC_IDS_PATH_IS_INVALID, szLabel);
			AfxMessageBox(strPrompt, MB_ICONEXCLAMATION);

			// Do this so that the control receives focus.
			(void) pDX->PrepareEditCtrl(nIDC);

			// Fail the call.
			strPrompt.Empty();	// exception prep
			pDX->Fail();
		}  // if:  path is invalid
	}  // if:  saving data

}  //*** DDV_Path()

/////////////////////////////////////////////////////////////////////////////
//++
//
//	CleanupLabel
//
//	Routine Description:
//		Prepare a label read from a dialog to be used as a string in a
//		message by removing ampersands (&) and colons (:).
//
//	Arguments:
//		pszLabel	[IN OUT] Label to be cleaned up.
//
//	Return Value:
//		None.
//
//--
/////////////////////////////////////////////////////////////////////////////
void CleanupLabel(LPTSTR pszLabel)
{
	LPTSTR	pIn, pOut;
	LANGID	langid;
	WORD	primarylangid;
	BOOL	bFELanguage;

	// Get the language ID.
	langid = GetUserDefaultLangID();
	primarylangid = (WORD) PRIMARYLANGID(langid);
	bFELanguage = ((primarylangid == LANG_JAPANESE)
					|| (primarylangid == LANG_CHINESE)
					|| (primarylangid == LANG_KOREAN));

	//
	// copy the name sans '&' and ':' chars
	//

	pIn = pOut = pszLabel;
	do
	{
		//
		// strip FE accelerators with parentheses. e.g. "foo(&F)" -> "foo"
		//
		if (   bFELanguage
			&& (pIn[0] == _T('('))
			&& (pIn[1] == _T('&'))
			&& (pIn[2] != _T('\0'))
			&& (pIn[3] == _T(')')))
		{
			pIn += 3;
		}
		else if ((*pIn != _T('&')) && (*pIn != _T(':')))
			*pOut++ = *pIn;
	} while (*pIn++ != _T('\0')) ;

}  //*** CleanupLabel()