//
//  Copyright © 2002, RESON Inc. All Rights Reserved.
//
//  No part of this file may be reproduced or transmitted in any form or by
//  any means, electronic or mechanical, including photocopy, recording, or
//  information storage or retrieval system, without permission in writing
//  from RESON Inc.
//
//  Filename:   6046HaspDlg.cpp
//
//  Project:    6046
//
//  Author(s):  W. Arcus.
//
//  Purpose:    
//
//  Notes:      
//


#include "StdAfx.h"
#include "6046Hasp.h"
#include "6046HaspDlg.h"
#include "RESON6046Hasp.h"
#include "6046Options.h"
#include "PassWordDlg.h"

#pragma warning( push, 3 )                  // Microsoft's STL is dirty at warning level 4 so drop back for its inclusion.
#include <vector>
#pragma warning( pop )

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:

    CAboutDlg();

// Dialog Data
    //{{AFX_DATA(CAboutDlg)
    enum { IDD = IDD_ABOUTBOX };
    //}}AFX_DATA

    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CAboutDlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    //}}AFX_VIRTUAL

// Implementation
protected:
    //{{AFX_MSG(CAboutDlg)
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
    //{{AFX_DATA_INIT(CAboutDlg)
    //}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CAboutDlg)
    //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
    //{{AFX_MSG_MAP(CAboutDlg)
        // No message handlers
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMy6046HaspDlg dialog

CMy6046HaspDlg::CMy6046HaspDlg(CWnd* pParent /*=NULL*/)
    : CDialog(CMy6046HaspDlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(CMy6046HaspDlg)
    m_bQCCheck = FALSE;
    m_bDemoMode = FALSE;
    m_bPLCEnable = FALSE;
    m_DongleExpirationDate = _T("");
    m_Version = _T("");
    m_KeyNumber = _T("");
    //}}AFX_DATA_INIT
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMy6046HaspDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CMy6046HaspDlg)
    DDX_Check(pDX, IDC_CHECK_DATA_QC, m_bQCCheck);
    DDX_Check(pDX, IDC_CHECK_DEMO, m_bDemoMode);
    DDX_Check(pDX, IDC_CHECK_PLC_ENABLE, m_bPLCEnable);
    DDX_Text(pDX, IDC_STATIC_EXPIRATION_DATE, m_DongleExpirationDate);
    DDX_Text(pDX, IDC_STATIC_VERSION, m_Version);
    DDX_Text(pDX, IDC_STATIC_KEY_NUMBER, m_KeyNumber);
    //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CMy6046HaspDlg, CDialog)
    //{{AFX_MSG_MAP(CMy6046HaspDlg)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_BUTTON_CLEAR_ALL, OnButtonClearAll)
    ON_BN_CLICKED(IDC_BUTTON_DUMP_REFRESH, OnButtonDumpRefresh)
	ON_BN_CLICKED(IDC_BUTTON_PROGRAM, OnButtonProgram)
	ON_BN_CLICKED(IDC_BUTTON_CLEAR_KEY, OnButtonClearKey)
	//}}AFX_MSG_MAP

    ON_MESSAGE( userMessageWelcome, Welcome )

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMy6046HaspDlg message handlers

BOOL CMy6046HaspDlg::OnInitDialog( void )
{
    CDialog::OnInitDialog();

    // Add "About..." menu item to system menu.

    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        CString strAboutMenu;
        strAboutMenu.LoadString(IDS_ABOUTBOX);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    SetIcon(m_hIcon, TRUE);         // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon

    Setup();

    PostMessage( userMessageWelcome );

    return TRUE;  // return TRUE unless you set the focus to a control
}

void CMy6046HaspDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialog::OnSysCommand(nID, lParam);
    }
}

void CMy6046HaspDlg::OnPaint( void )
{
    // If you add a minimize button to your dialog, you will need the code below
    //  to draw the icon.  For MFC applications using the document/view model,
    //  this is automatically done for you by the framework.

    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialog::OnPaint();
    }
}

HCURSOR CMy6046HaspDlg::OnQueryDragIcon( void )
{
    return (HCURSOR) m_hIcon;
}

void CMy6046HaspDlg::OnCancel( void )
{
    if ( DoesUserWishToExit() )
    {
        CDialog::OnCancel();
    }
}

void CMy6046HaspDlg::OnOK( void )
{
    if ( DoesUserWishToExit() )
    {
        CDialog::OnOK();
    }
}

inline
bool CMy6046HaspDlg::DoesUserWishToExit( void ) const
{
    return ( AfxMessageBox( _T( "Are you sure you wish to exit ?" ), MB_YESNO ) == IDYES );
}

void CMy6046HaspDlg::OnButtonProgram( void )
{
    CString ErrorMsg;

    try
    {
        {
            CWaitCursor WaitCursor;

            UpdateData( TRUE );

            // Initialize the 6046's options area and set key options according to GUI state.

            InitializeKey( ( m_bDemoMode != FALSE ) );

            C6046HaspOptions Key;

            Key.SetPayloadControllerEnable( ( m_bPLCEnable != FALSE ) );
        }

        OnButtonDumpRefresh();
    }
    catch ( const CHaspException &rException )
    {
        ErrorMsg = HaspError( rException );
    }
    catch ( ... )
    {
        ErrorMsg = _T( "Unspecfied error" );
    }

    if ( ! ErrorMsg.IsEmpty() )
    {
        AfxMessageBox( ErrorMsg, MB_OK );
    }
}

void CMy6046HaspDlg::OnButtonClearAll( void )
{
    m_bDemoMode  = FALSE;
    m_bPLCEnable = TRUE;
    m_bQCCheck   = FALSE;

    UpdateData( FALSE );
}

void CMy6046HaspDlg::OnButtonDumpRefresh( void )
{
    CString ErrorMsg;

    try
    {
        CWaitCursor WaitCursor;

        // First get the general key attributes (dump area of the UI).

        {
            CRESON6046Hasp Key;

            m_Version.Format( "%u", Key.SecureCheck( CRESON6046Hasp::haspLayoutVersion ) );

            time_t lDemoTime = Key.ReadLong( CRESON6046Hasp::haspLayoutDemoTimeUpper );

            if ( lDemoTime == 0L )
            {
                m_DongleExpirationDate = _T( "Does not expire" );
            }
            else if ( lDemoTime != -1 )
            {
                m_DongleExpirationDate.Format( "%s", CTime( lDemoTime ).FormatGmt("%d %b %Y") );
            }
            else
            {
                ErrorMsg = _T( "Can't read key demo time" );
            }

            m_KeyNumber.Format( "%ld", Key.HaspID() );
        }

        // Next read the 6046 options area.

        {
            C6046HaspOptions Key;

            m_bPLCEnable = Key.IsPayloadControllerEnabled();
        }

        UpdateData( FALSE );
    }
    catch ( const CHaspException &rException )
    {
        ErrorMsg = HaspError( rException );
    }
    catch ( ... )
    {
        ErrorMsg = _T( "Unspecified error" );
    }

    if ( ! ErrorMsg.IsEmpty() )
    {
        ::AfxMessageBox( ErrorMsg, MB_OK | MB_ICONEXCLAMATION );
    }
}

void CMy6046HaspDlg::Setup( void )
{
    // Now, ensure we have a RESON key present before we continue.

    while ( ! IsValidDongleConnected() )
    {
        if ( ::AfxMessageBox( _T( "No valid RESON HASP Key has been detected!\n Please connect a valid key to continue." ), MB_RETRYCANCEL | MB_ICONEXCLAMATION ) == IDCANCEL )
        {
            ::PostQuitMessage( -1 );
            return;
        }
    }

    // Ok, now update the dialog state from the key's properties etc.

    m_bQCCheck              = FALSE;
    m_bDemoMode             = FALSE;
    m_bPLCEnable            = FALSE;

    m_DongleExpirationDate  = _T("");
    m_Version               = _T("");
    m_KeyNumber             = _T("");

    OnButtonDumpRefresh();
}

inline
bool CMy6046HaspDlg::IsValidDongleConnected( void ) const
{
    bool bValidKey = false;

    try
    {
        CRESON6046Hasp Key;
        bValidKey = ( Key.IsTimeHasp() != 0 );
    }
    catch ( CHaspException Exception )
    {
        bValidKey = false;
        TRACE( _T( "IsValidDongleConnected(), %s.\n" ), HaspError( Exception ) );
    }
    catch ( ... )
    {
        bValidKey = false;
        TRACE( _T( "IsValidDongleConnected(), Unspecified exception caught\n" ) );
    }

    return bValidKey;
}

inline
CString CMy6046HaspDlg::HaspError( const CHaspException &rException ) const
{
    CString ErrorMsg;

    switch( rException.GetStatus() )
    {
        case -12:

            ErrorMsg = _T( "Pass keys incorrect." );
            break;

        case -3:
        case -1002:

            ErrorMsg = _T( "No HASP connected." );
            break;

        default:

            ErrorMsg.Format( _T( "HASP error, status code: %d" ), rException.GetStatus() );
            break;
    }

    return ErrorMsg;
}

inline
void CMy6046HaspDlg::InitializeKey( const bool &rbDemoMode ) const
{
    std::vector<WORD> Memory6046Options( 16, 0x0000 );

    ASSERT( Memory6046Options.size() == 16 );


    // Set the 6046 options bit pattern as necessary.

    //  ... nothing to do for now.

    // Construct the key object and configure it.

    CRESON6046Hasp Key;

    Key.Configure(  CRESON6046Hasp::resonHaspVersion4,                      // Version 4 layout.
                        false,                                              // Clear all HASP memory.
                            &Memory6046Options[ 0 ],                        // Write 6046 attributes.
                                Memory6046Options.size(),                   // Ditto.
                                    CRESON6046Hasp::haspLayoutPLCOptions,   // Block starts at PLC options.
                                        rbDemoMode );                       // Set demo mode (expires system time + 30 days).

}


void CMy6046HaspDlg::OnButtonClearKey( void )
{
    if ( ::AfxMessageBox( _T( "Clearing the key will reset all of the key's memory (including non-6046 options) !\n\nContinue ?" ), MB_YESNO ) == IDYES )
    {
        CString ErrorMsg;

        try
        {
            {
                CWaitCursor WaitCursor;

                CRESON6046Hasp Key;

                Key.Configure(  CRESON6046Hasp::resonHaspVersion4,                      // Version 4 layout.
                                    true,                                               // Clear all HASP memory.
                                        NULL,                                           // Write 6046 attributes.
                                            0,                                          // Ditto.
                                                CRESON6046Hasp::haspLayoutPLCOptions,   // Block starts at PLC options.
                                                    true );                             // Set demo mode (expires system time + 30 days).

            }

            OnButtonDumpRefresh();
        }
        catch ( const CHaspException &rException )
        {
            ErrorMsg = HaspError( rException );
        }
        catch ( ... )
        {
            ErrorMsg = _T( "Unspecified error" );
        }

        if ( ! ErrorMsg.IsEmpty() )
        {
            ::AfxMessageBox( ErrorMsg, MB_OK | MB_ICONEXCLAMATION );
        }
    }
}

afx_msg LONG CMy6046HaspDlg::Welcome( WPARAM wParam, LPARAM lParam )
{
    UNREFERENCED_PARAMETER( wParam );
    UNREFERENCED_PARAMETER( lParam );

    CAboutDlg AboutDlg;
    AboutDlg.DoModal();

    return 1L;
}


