/****************************************************************************
File    : CheatDlg.cpp
/*
@(#) #SY# Atari800Win PLus
@(#) #IS# CCheatDlg implementation file
@(#) #BY# Tomasz Szymankowski
@(#) #LM# 23.03.2002
*/

#include "StdAfx.h"
#include "Atari800Win.h"
#include "Helpers.h"
#include "CheatDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define IDC_CHEAT_FIRST		IDC_CHEAT_DISABLECOLLISIONS
#define IDC_CHEAT_LAST		IDC_CHEAT_CANCEL

#define MAX_MEMO			255
#define MAX_SEARCH			255
#define MAX_LOCK			255


/////////////////////////////////////////////////////////////////////////////
// CCheatDlg dialog

BEGIN_MESSAGE_MAP(CCheatDlg, CCommonDlg)
	//{{AFX_MSG_MAP(CCheatDlg)
	ON_BN_CLICKED(IDC_CHEAT_DISABLECOLLISIONS, OnDisableCollisions)
	ON_BN_CLICKED(IDC_CHEAT_PLAYERPLAYER, OnPlayerPlayer)
	ON_BN_CLICKED(IDC_CHEAT_PLAYERPLAYFIELD, OnPlayerPlayfield)
	ON_BN_CLICKED(IDC_CHEAT_MISSILEPLAYER, OnMissilePlayer)
	ON_BN_CLICKED(IDC_CHEAT_MISSILEPLAYFIELD, OnMissilePlayfield)
	ON_BN_CLICKED(IDC_CHEAT_SEARCH_BUTTON, OnSearchButton)
	ON_BN_CLICKED(IDC_CHEAT_MEMO_BUTTON, OnMemoButton)
	ON_NOTIFY(UDN_DELTAPOS, IDC_CHEAT_MEMO_SPIN, OnDeltaposMemoSpin)
	ON_EN_KILLFOCUS(IDC_CHEAT_MEMO, OnKillfocusMemo)
	ON_NOTIFY(UDN_DELTAPOS, IDC_CHEAT_SEARCH_SPIN, OnDeltaposSearchSpin)
	ON_EN_KILLFOCUS(IDC_CHEAT_SEARCH, OnKillfocusSearch)
	ON_NOTIFY(UDN_DELTAPOS, IDC_CHEAT_LOCK_SPIN, OnDeltaposLockSpin)
	ON_EN_KILLFOCUS(IDC_CHEAT_LOCK, OnKillfocusLock)
	ON_NOTIFY(LVN_ITEMCHANGED, IDC_CHEAT_POKELIST, OnItemchangedPokeList)
	ON_BN_CLICKED(IDC_CHEAT_LOCK_CHECK, OnLockCheck)
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_CHEAT_OK, OnOK)
	ON_BN_CLICKED(IDC_CHEAT_CANCEL, CCommonDlg::OnCancel)
END_MESSAGE_MAP()

/*========================================================
Method   : CCheatDlg::CCheatDlg
=========================================================*/
/* #FN#
   Standard constructor */
CCheatDlg::
CCheatDlg(
	CCheatServer *pCheatServer,
	CWnd *pParent /*=NULL*/ /* #IN# Pointer to the parent window */
)
	: CCommonDlg( CCheatDlg::IDD, pParent )
{
	//{{AFX_DATA_INIT(CCheatDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT

	m_pCheatServer    = pCheatServer;
	m_bTrainerChanged = FALSE;
	m_bListNotify     = FALSE;
	m_nFirstCtrl      = IDC_CHEAT_FIRST;
	m_nLastCtrl       = IDC_CHEAT_LAST;

	m_bFontCreated = m_fontList.CreateFont(
		g_bLargeFonts ? 16 : 13,
		0, 0, 0,
		FW_NORMAL,
		0, 0, 0,
		DEFAULT_CHARSET,
		OUT_DEFAULT_PRECIS,
		CLIP_DEFAULT_PRECIS,
		DEFAULT_QUALITY,
		DEFAULT_PITCH,
		"Courier New"
	);
} /* #OF# CCheatDlg::CCheatDlg */

/*========================================================
Method   : CCheatDlg::~CCheatDlg
=========================================================*/
/* #FN#
   Destructor */
CCheatDlg::
~CCheatDlg()
{
	/* Done with the font, so delete the font object */
	if( m_bFontCreated )
		m_fontList.DeleteObject();
} /* #OF# CCheatDlg::~CCheatDlg */

/*========================================================
Method   : CCheatDlg::DoDataExchange
=========================================================*/
/* #FN#
   Dynamic Data Exchange */
void
/* #AS#
   Nothing */
CCheatDlg::
DoDataExchange(
	CDataExchange *pDX /* #IN# Pointer to CDataExchange object */
)
{
	CCommonDlg::DoDataExchange( pDX );
	//{{AFX_DATA_MAP(CCheatDlg)
	DDX_Control(pDX, IDC_CHEAT_POKELIST, m_listPoke);
	//}}AFX_DATA_MAP
} /* #OF# CCheatDlg::DoDataExchange */


/////////////////////////////////////////////////////////////////////////////
// CCheatDlg implementation

/*========================================================
Method   : CCheatDlg::SetDlgState
=========================================================*/
/* #FN#
   Sets up the state of the dialog controls */
void
/* #AS#
   Nothing */
CCheatDlg::
SetDlgState()
{
	CButton	*pButton  = NULL;
	CWnd    *pWnd     = NULL;
	BOOL     bChecked = CheckedItemsCount( TRUE ) > 0;
	BOOL     bItems   = m_listPoke.GetItemCount() > 0;

	ASSERT(m_pCheatServer);

	/* Set up collision group state */
	if( m_ulMiscState & MS_DISABLE_COLLISIONS )
	{
		pButton = (CButton *)GetDlgItem( IDC_CHEAT_DISABLECOLLISIONS );
		ASSERT(pButton);
		pButton->SetCheck( 1 );
	}
	pButton = (CButton *)GetDlgItem( IDC_CHEAT_PLAYERPLAYER );
	ASSERT(pButton);
	if( m_ulCollisions & DC_PLAYER_PLAYER )
		pButton->SetCheck( 1 );
	pButton->EnableWindow( m_ulMiscState & MS_DISABLE_COLLISIONS );

	pButton = (CButton *)GetDlgItem( IDC_CHEAT_PLAYERPLAYFIELD );
	ASSERT(pButton);
	if( m_ulCollisions & DC_PLAYER_PLAYFIELD )
		pButton->SetCheck( 1 );
	pButton->EnableWindow( m_ulMiscState & MS_DISABLE_COLLISIONS );

	pButton = (CButton *)GetDlgItem( IDC_CHEAT_MISSILEPLAYER );
	ASSERT(pButton);
	if( m_ulCollisions & DC_MISSILE_PLAYER )
		pButton->SetCheck( 1 );
	pButton->EnableWindow( m_ulMiscState & MS_DISABLE_COLLISIONS );

	pButton = (CButton *)GetDlgItem( IDC_CHEAT_MISSILEPLAYFIELD );
	ASSERT(pButton);
	if( m_ulCollisions & DC_MISSILE_PLAYFIELD )
		pButton->SetCheck( 1 );
	pButton->EnableWindow( m_ulMiscState & MS_DISABLE_COLLISIONS );

	/* Set up trainer group state */
	pButton = (CButton *)GetDlgItem( IDC_CHEAT_LOCK_CHECK );
	ASSERT(pButton);
	pButton->EnableWindow( bChecked );
	pButton->SetCheck( (m_ulMiscState & MS_CHEAT_LOCK) != 0 );

	pWnd = GetDlgItem( IDC_CHEAT_LOCK );
	ASSERT(pWnd);
	pWnd->EnableWindow( bChecked && m_ulMiscState & MS_CHEAT_LOCK );

	pWnd = GetDlgItem( IDC_CHEAT_LOCK_SPIN );
	ASSERT(pWnd);
	pWnd->EnableWindow( bChecked && m_ulMiscState & MS_CHEAT_LOCK );

	pWnd = GetDlgItem( IDC_CHEAT_SEARCH_BUTTON );
	ASSERT(pWnd);
	pWnd->EnableWindow( m_pCheatServer->GetMemoCount() );

	pWnd = GetDlgItem( IDC_CHEAT_SEARCH );
	ASSERT(pWnd);
	pWnd->EnableWindow( m_pCheatServer->GetMemoCount() );

	pWnd = GetDlgItem( IDC_CHEAT_SEARCH_SPIN );
	ASSERT(pWnd);
	pWnd->EnableWindow( m_pCheatServer->GetMemoCount() );

	m_listPoke.EnableWindow( bItems );

	SetDlgItemInt( IDC_CHEAT_MEMO,   m_nMemo,   FALSE );
	SetDlgItemInt( IDC_CHEAT_SEARCH, m_nSearch, FALSE );
	SetDlgItemInt( IDC_CHEAT_LOCK,   m_nLock,   FALSE );
} /* #OF# CCheatDlg::SetDlgState */

/*========================================================
Method   : CCheatDlg::CheckedItemsCount
=========================================================*/
/* #FN#
   Counts the number of checked items of the list */
int
/* #AS#
   Number of checked items */
CCheatDlg::
CheckedItemsCount(
	BOOL bCheckIfAny /*=FALSE*/
)
{
	int nCount = 0;

	for( int i = 0; i < m_listPoke.GetItemCount(); i++ )
	{
		if( m_listPoke.GetCheck( i ) )
		{
			nCount++;
			if( bCheckIfAny )
				break;
		}
	}
	return nCount;
} /* #OF# CCheatDlg::CheckedItemsCount */

/*========================================================
Method   : CCheatDlg::EnableListUpdates
=========================================================*/
/* #FN#
   Enables or disables list control redrawing */
void
/* #AS#
   Nothing */
CCheatDlg::
EnableListUpdates(
	BOOL bEnable /*=TRUE*/
)
{
	m_listPoke.SetRedraw( bEnable );
	/* Show the changes */
	if( bEnable )
		m_listPoke.Invalidate();

	m_bListNotify = bEnable;
} /* #OF# CCheatDlg::EnableListUpdates */


/////////////////////////////////////////////////////////////////////////////
// CCheatDlg message handlers

/*========================================================
Method   : CCheatDlg::OnInitDialog
=========================================================*/
/* #FN#
   Performs special processing when the dialog box is initialized */
BOOL
/* #AS#
   TRUE unless you set the focus to a control */
CCheatDlg::
OnInitDialog()
{
	CCommonDlg::OnInitDialog();

	m_ulMiscState  = g_Misc.ulState;
	m_ulCollisions = g_Misc.Cheat.ulCollisions;
	m_nMemo        = g_Misc.Cheat.nMemo;
	m_nSearch      = g_Misc.Cheat.nSearch;
	m_nLock        = g_Misc.Cheat.nLock;

	/* We need a list control with checkboxes */
	ListView_SetExtendedListViewStyle( m_listPoke.m_hWnd, LVS_EX_CHECKBOXES );

	/* Fixed fonts would be appreciated */
	if( m_bFontCreated )
		m_listPoke.SetFont( &m_fontList );

	/* Populate the address list control */
	_CursorBusy();

	EnableListUpdates( FALSE );
	m_pCheatServer->ListToCtrl( &m_listPoke );
	EnableListUpdates();

	_CursorFree();

	SetDlgState();

	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
} /* #OF# CCheatDlg::OnInitDialog */

/*========================================================
Method   : CCheatDlg::OnItemchangedPokeList
=========================================================*/
/* #FN#
   Called by framework when a item of the list control changes */
void
/* #AS#
   Nothing */
CCheatDlg::
OnItemchangedPokeList(
	NMHDR   *pNMHDR, /* #IN#  */
	LRESULT *pResult /* #OUT# */
)
{
	if( m_bListNotify )
	{
		NM_LISTVIEW *pNMListView = (NM_LISTVIEW*)pNMHDR;

		/* We are looking only for changes of state of a check box */
		if( (pNMListView->uNewState & LVIS_STATEIMAGEMASK) !=
			(pNMListView->uOldState & LVIS_STATEIMAGEMASK) )
		{
			m_bTrainerChanged = TRUE;
			SetDlgState();
		}
	}
	*pResult = 0;
} /* #OF# CCheatDlg::OnItemchangedPokeList */

/*========================================================
Method   : CCheatDlg::OnDisableCollisions
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate check box */
void
/* #AS#
   Nothing */
CCheatDlg::
OnDisableCollisions()
{
	_ClickButton( IDC_CHEAT_DISABLECOLLISIONS, m_ulMiscState, MS_DISABLE_COLLISIONS );
	/* Set the activity of other controls of the collisions group */
	SetDlgState();
} /* #OF# CCheatDlg::OnDisableCollisions */

/*========================================================
Method   : CCheatDlg::OnPlayerPlayer
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate check box */
void
/* #AS#
   Nothing */
CCheatDlg::
OnPlayerPlayer()
{
	_ClickButton( IDC_CHEAT_PLAYERPLAYER, m_ulCollisions, DC_PLAYER_PLAYER );
} /* #OF# CCheatDlg::OnPlayerPlayer */

/*========================================================
Method   : CCheatDlg::OnPlayerPlayfield
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate check box */
void
/* #AS#
   Nothing */
CCheatDlg::
OnPlayerPlayfield()
{
	_ClickButton( IDC_CHEAT_PLAYERPLAYFIELD, m_ulCollisions, DC_PLAYER_PLAYFIELD );
} /* #OF# CCheatDlg::OnPlayerPlayfield */

/*========================================================
Method   : CCheatDlg::OnMissilePlayer
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate check box */
void
/* #AS#
   Nothing */
CCheatDlg::
OnMissilePlayer()
{
	_ClickButton( IDC_CHEAT_MISSILEPLAYER, m_ulCollisions, DC_MISSILE_PLAYER );
} /* #OF# CCheatDlg::OnMissilePlayer */

/*========================================================
Method   : CCheatDlg::OnMissilePlayfield
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate check box */
void
/* #AS#
   Nothing */
CCheatDlg::
OnMissilePlayfield()
{
	_ClickButton( IDC_CHEAT_MISSILEPLAYFIELD, m_ulCollisions, DC_MISSILE_PLAYFIELD );
} /* #OF# CCheatDlg::OnMissilePlayfield */

/*========================================================
Method   : CCheatDlg::OnMemoButton
=========================================================*/
/* #FN#
   Builds a list of addresses containing a given value */
void
/* #AS#
   Nothing */
CCheatDlg::
OnMemoButton()
{
	_CursorBusy();

	m_pCheatServer->ShotMemo( m_nMemo, memory, 65536 );
	m_bTrainerChanged = TRUE;

	EnableListUpdates( FALSE );
	m_listPoke.DeleteAllItems();
	EnableListUpdates();

	_CursorFree();

	SetDlgState();
} /* #OF# CCheatDlg::OnMemoButton */

/*========================================================
Method   : CCheatDlg::OnSearchButton
=========================================================*/
/* #FN#
   Builds a list of addresses with changed values */
void
/* #AS#
   Nothing */
CCheatDlg::
OnSearchButton()
{
	_CursorBusy();

	m_pCheatServer->ShotAddr( m_nSearch );
	m_bTrainerChanged = TRUE;

	EnableListUpdates( FALSE );
	m_pCheatServer->ListToCtrl( &m_listPoke );
	EnableListUpdates();

	_CursorFree();

	SetDlgState();
} /* #OF# CCheatDlg::OnSearchButton */

/*========================================================
Method   : CCheatDlg::OnDeltaposMemoSpin
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate spin control */
void
/* #AS#
   Nothing */
CCheatDlg::
OnDeltaposMemoSpin(
	NMHDR   *pNMHDR, /* #IN#  */
	LRESULT *pResult /* #OUT# */
)
{
	_DeltaposSpin( pNMHDR, IDC_CHEAT_MEMO, m_nMemo, 0, MAX_MEMO );
	*pResult = 0;
} /* #OF# CCheatDlg::OnDeltaposMemoSpin */

/*========================================================
Method   : CCheatDlg::OnKillfocusMemo
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate edit control */
void
/* #AS#
   Nothing */
CCheatDlg::
OnKillfocusMemo()
{
	_KillfocusSpin( IDC_CHEAT_MEMO, m_nMemo, 0, MAX_MEMO );
} /* #OF# CCheatDlg::OnKillfocusMemo */

/*========================================================
Method   : CCheatDlg::OnDeltaposSearchSpin
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate spin control */
void
/* #AS#
   Nothing */
CCheatDlg::
OnDeltaposSearchSpin(
	NMHDR   *pNMHDR, /* #IN#  */
	LRESULT *pResult /* #OUT# */
)
{
	_DeltaposSpin( pNMHDR, IDC_CHEAT_SEARCH, m_nSearch, 0, MAX_SEARCH );
	*pResult = 0;
} /* #OF# CCheatDlg::OnDeltaposSearchSpin */

/*========================================================
Method   : CCheatDlg::OnKillfocusSearch
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate edit control */
void
/* #AS#
   Nothing */
CCheatDlg::
OnKillfocusSearch()
{
	_KillfocusSpin( IDC_CHEAT_SEARCH, m_nSearch, 0, MAX_SEARCH );
} /* #OF# CCheatDlg::OnKillfocusSearch */

/*========================================================
Method   : CCheatDlg::OnLockCheck
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate check box */
void
/* #AS#
   Nothing */
CCheatDlg::
OnLockCheck()
{
	_ClickButton( IDC_CHEAT_LOCK_CHECK, m_ulMiscState, MS_CHEAT_LOCK );
	/* Set the activity of the edit and spin lock controls */
	SetDlgState();
} /* #OF# CCheatDlg::OnLockCheck */

/*========================================================
Method   : CCheatDlg::OnDeltaposLockSpin
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate spin control */
void
/* #AS#
   Nothing */
CCheatDlg::
OnDeltaposLockSpin(
	NMHDR   *pNMHDR, /* #IN#  */
	LRESULT *pResult /* #OUT# */
)
{
	_DeltaposSpin( pNMHDR, IDC_CHEAT_LOCK, m_nLock, 0, MAX_LOCK );
	*pResult = 0;
} /* #OF# CCheatDlg::OnDeltaposLockSpin */

/*========================================================
Method   : CCheatDlg::OnKillfocusLock
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate edit control */
void
/* #AS#
   Nothing */
CCheatDlg::
OnKillfocusLock()
{
	_KillfocusSpin( IDC_CHEAT_LOCK, m_nLock, 0, MAX_LOCK );
} /* #OF# CCheatDlg::OnKillfocusLock */

/*========================================================
Method   : CCheatDlg::ReceiveFocused
=========================================================*/
/* #FN#
   Receive the edit controls content again. The user could press
   'Enter' or 'Alt-O' and then all changes he's made in the last
   edited control would be lost. */
void
/* #AS#
   Nothing */
CCheatDlg::
ReceiveFocused()
{
	CWnd *pWnd    = GetFocus();
	UINT  nCtrlID = pWnd ? pWnd->GetDlgCtrlID() : 0;

	switch( nCtrlID )
	{
		case IDC_CHEAT_MEMO:
			OnKillfocusMemo();
			break;
		case IDC_CHEAT_SEARCH:
			OnKillfocusSearch();
			break;
		case IDC_CHEAT_LOCK:
			OnKillfocusLock();
			break;
	}
} /* #OF# CCheatDlg::ReceiveFocused */

/*========================================================
Method   : CCheatDlg::OnOK
=========================================================*/
/* #FN#
   Called when the user clicks the OK button */
void
/* #AS#
   Nothing */
CCheatDlg::
OnOK()
{
	/* Unfortunately, edit controls do not lose the focus before
	   handling this when the user uses accelerators */
	ReceiveFocused();

	/* Update the list of locked registers */
	if( m_bTrainerChanged )
	{
		_CursorBusy();
		m_pCheatServer->CtrlToList( &m_listPoke );
		_CursorFree();
	}
	if( m_ulCollisions != g_Misc.Cheat.ulCollisions )
	{
		g_Misc.Cheat.ulCollisions = m_ulCollisions;
		WriteRegDWORD( NULL, REG_CHEAT_COLLISIONS, g_Misc.Cheat.ulCollisions );
	}
	if( m_nMemo != g_Misc.Cheat.nMemo )
	{
		g_Misc.Cheat.nMemo = m_nMemo;
		WriteRegDWORD( NULL, REG_CHEAT_MEMO, g_Misc.Cheat.nMemo );
	}
	if( m_nSearch != g_Misc.Cheat.nSearch )
	{
		g_Misc.Cheat.nSearch = m_nSearch;
		WriteRegDWORD( NULL, REG_CHEAT_SEARCH, g_Misc.Cheat.nSearch );
	}
	if( m_nLock != g_Misc.Cheat.nLock )
	{
		g_Misc.Cheat.nLock = m_nLock;
		WriteRegDWORD( NULL, REG_CHEAT_LOCK, g_Misc.Cheat.nLock );
	}
	if( m_ulMiscState != g_Misc.ulState )
	{
		g_Misc.ulState = m_ulMiscState;
		WriteRegDWORD( NULL, REG_MISC_STATE, g_Misc.ulState );
	}
	CCommonDlg::OnOK();
} /* #OF# CCheatDlg::OnOK */
