/*++

   Copyright    (c)    1994-1998    Microsoft Corporation

   Module  Name :

        ddxv.cpp

   Abstract:

        DDX/DDV Routines

   Author:

        Ronald Meijer (ronaldm)

   Project:

        Internet Services Manager

   Revision History:

--*/

//
// Include Files
//
#include "stdafx.h"
#include "comprop.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

//
// Prototype for external function
//
void AFXAPI AfxSetWindowText(HWND hWndCtrl, LPCTSTR lpszNew);

//
// Numeric strings cannot be longer than 32 digits
//
#define NUMERIC_BUFF_SIZE (32)

//
// Dummy password used for display purposes
//
LPCTSTR g_lpszDummyPassword = _T("**********");



void 
AFXAPI DDV_MinChars(
    IN CDataExchange * pDX,
    IN CString const & value,
    IN int nChars
    )
/*++

Routine Description:

    Validate CString using a minimum string length

Arguments:

    CDataExchange * pDX   : Data exchange structure
    CString const & value : String to be validated
    int nChars            : Minimum length of string

Return Value:

    None

--*/
{
    if (pDX->m_bSaveAndValidate && value.GetLength() < nChars)
    {
        TCHAR szT[NUMERIC_BUFF_SIZE + 1];
        wsprintf(szT, _T("%d"), nChars);
        CString prompt;
        ::AfxFormatString1(prompt, IDS_DDX_MINIMUM, szT);
        ::AfxMessageBox(prompt, MB_ICONEXCLAMATION, IDS_DDX_MINIMUM);
        //
        // exception prep
        //
        prompt.Empty(); 
        pDX->Fail();
    }
}



void 
AFXAPI DDV_MinMaxChars(
    IN CDataExchange * pDX,
    IN CString const & value,
    IN int nMinChars,
    IN int nMaxChars
    )
/*++

Routine Description:

    Validate CString using a minimum and maximum string length.

Arguments:

    CDataExchange * pDX   : Data exchange structure
    CString const & value : String to be validated
    int nMinChars         : Minimum length of string
    int nMaxChars         : Maximum length of string

Return Value:

    None

--*/
{
    if (pDX->m_bSaveAndValidate)
    {
        UINT nID;
        TCHAR szT[NUMERIC_BUFF_SIZE + 1];

        if (value.GetLength() < nMinChars)
        {
            nID = IDS_DDX_MINIMUM;
            ::wsprintf(szT, _T("%d"), nMinChars);
        }
        else if (value.GetLength() > nMaxChars)
        {
            nID = AFX_IDP_PARSE_STRING_SIZE;
            ::wsprintf(szT, _T("%d"), nMaxChars);
        }
        else
        {
            //
            // Passes both our tests, it's ok.
            //
            return;
        }

        CString prompt;
        ::AfxFormatString1(prompt, nID, szT);
        ::AfxMessageBox(prompt, MB_ICONEXCLAMATION, nID);

        //
        // exception prep
        //
        prompt.Empty(); 

        pDX->Fail();
    }
    else if (pDX->m_hWndLastControl != NULL && pDX->m_bEditLastControl)
    {
        //
        // limit the control max-chars automatically
        //
        ::SendMessage(pDX->m_hWndLastControl, EM_LIMITTEXT, nMaxChars, 0);
    }
}



void 
AFXAPI DDX_Spin(
    IN CDataExchange * pDX,
    IN int nIDC,
    IN OUT int & value
    )
/*++

Routine Description:

    Save/store data from spinbutton control

Arguments:

    CDataExchange * pDX : Data exchange structure
    int nIDC            : Control ID of the spinbutton control
    int & value         : Value to be saved or stored

Return Value:

    None

--*/
{
    HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
    if (pDX->m_bSaveAndValidate)
    {
        value = (int)LOWORD(::SendMessage(hWndCtrl, UDM_GETPOS, 0, 0L));
    }
    else
    {
        ::SendMessage(hWndCtrl, UDM_SETPOS, 0, MAKELPARAM(value, 0));
    }
}



void 
AFXAPI DDV_MinMaxSpin(
    IN CDataExchange * pDX,
    IN HWND hWndControl,
    IN int minVal,
    IN int maxVal
    )
/*++

Routine Description:

    Enforce minimum/maximum spin button range

Arguments:

    CDataExchange * pDX : Data exchange structure
    HWND hWndControl    : Control window handle
    int minVal          : Minimum value
    int maxVal          : Maximum value

Return Value:

    None

Note:

    Unlike most data validation routines, this one
    MUST be used prior to an accompanying DDX_Spin()
    function.  This is because spinbox controls have a
    native limit of 0-100.  Also, this function requires
    a window handle to the child control.  The
    CONTROL_HWND macro can be used for this.

--*/
{
    ASSERT(minVal <= maxVal);
    if (!pDX->m_bSaveAndValidate && hWndControl != NULL)
    {
        //
        // limit the control range automatically
        //
        ::SendMessage(hWndControl, UDM_SETRANGE, 0, MAKELPARAM(maxVal, minVal));
    }
}



void 
AFXAPI DDX_Password(
    IN CDataExchange * pDX,
    IN int nIDC,
    IN OUT CString & value,
    IN LPCTSTR lpszDummy
    )
/*++

Routine Description:

    DDX_Text for passwords.  Always display a dummy string
    instead of the real password, and ask for confirmation
    if the password has changed

Arguments:

    CDataExchange * pDX : Data exchange structure
    int nIDC            : Control ID
    CString & value     : value
    LPCTSTR lpszDummy   : Dummy password string to be displayed

Return Value:

    None

--*/
{
    HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
    if (pDX->m_bSaveAndValidate)
    {
        if (!::SendMessage(hWndCtrl, EM_GETMODIFY, 0, 0))
        {
            TRACEEOLID("No changes -- skipping");
            return;
        }

        CString strNew;
        int nLen = ::GetWindowTextLength(hWndCtrl);
        ::GetWindowText(hWndCtrl, strNew.GetBufferSetLength(nLen), nLen + 1);
        strNew.ReleaseBuffer();

        /*
        if (strNew == value)
        {
            TRACEEOLID("Password already matches -- skipping");
            return;
        }
        */

        //
        // Password has changed -- ask for confirmation
        //
        CConfirmDlg dlg;
        if (dlg.DoModal() == IDOK)
        {
            if (strNew.Compare(dlg.GetPassword()) == 0)
            {
                //
                // Password ok, pass it on
                //
                value = strNew;
                return;
            }
            else
            {
                //
                // No match, bad password
                //
                ::AfxMessageBox(IDS_PASSWORD_NO_MATCH);
            }
        }

        //
        // throw exception
        //
        pDX->Fail();        
    }
    else
    {
        //
        // Put the dummy password string in the edit control
        //
        if (!value.IsEmpty())
        {
            ::AfxSetWindowText(hWndCtrl, lpszDummy);
        }
    }
}



void 
AFXAPI DDX_Text(
    IN CDataExchange * pDX,
    IN int nIDC,
    IN OUT CILong & value
    )
/*++

Routine Description:

    DDX_Text for CILong class.  CILong takes care of all the dirty
    work for output and input.

Arguments:

    CDataExchange * pDX : Data exchange structure
    int nIDC            : Control ID code
    CILong & value      : value

Return Value:

    None

--*/
{
    HWND hWndCtrl = pDX->PrepareEditCtrl(nIDC);
    pDX->m_bEditLastControl = TRUE;

    TCHAR szT[NUMERIC_BUFF_SIZE + 1];

    if (pDX->m_bSaveAndValidate)
    {
        LONG l;

        ::GetWindowText(hWndCtrl, szT, NUMERIC_BUFF_SIZE);
        
        if (CINumber::ConvertStringToLong(szT, l))
        {
            value = l;
        }
        else
        {
            HINSTANCE hOld = AfxGetResourceHandle();
            AfxSetResourceHandle(GetModuleHandle(COMPROP_DLL_NAME));

            ::AfxMessageBox(IDS_INVALID_NUMBER);

            AfxSetResourceHandle(hOld);

            //
            // Throw exception
            //
            pDX->Fail();
        }
    }
    else
    {
        ::wsprintf(szT, _T("%s"), (LPCTSTR)value);
        ::AfxSetWindowText(hWndCtrl, szT);
    }
}



CConfirmDlg::CConfirmDlg(
    IN CWnd * pParent OPTIONAL
    )
/*++

Routine Description:

    Constructor for the confirmation dialog -- brought up by the password ddx
    whenever password confirmation is necessary.

Arguments:

    CWnd * pParent : Optional parent window

Return Value:

    None

--*/
    : CDialog(CConfirmDlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(CConfirmDlg)
    m_strPassword = _T("");
    //}}AFX_DATA_INIT
}



void 
CConfirmDlg::DoDataExchange(
    IN CDataExchange * pDX
    )
/*++

Routine Description:

    Initialise/Store control data

Arguments:

    CDataExchange* pDX - DDX/DDV control structure

Return Value:

    N/A

--*/
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CConfirmDlg)
    DDX_Text(pDX, IDC_EDIT_CONFIRM_PASSWORD, m_strPassword);
    //}}AFX_DATA_MAP
}



//
// Message Handlers
//
BEGIN_MESSAGE_MAP(CConfirmDlg, CDialog)
    //{{AFX_MSG_MAP(CConfirmDlg)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()