/****************************************************************************
File    : JoystickDlg.cpp
/*
@(#) #SY# Atari800Win PLus
@(#) #IS# CJoystickDlg implementation file
@(#) #BY# Richard Lawrence, Tomasz Szymankowski
@(#) #LM# 17.03.2002
*/

#include "StdAfx.h"
#include "Atari800Win.h"
#include "Helpers.h"
#include "WarningDlg.h"
#include "KeysetDlg.h"
#include "JoystickAdvDlg.h"
#include "JoystickDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define IDC_JOYSTICK_FIRST		IDC_JOYSTICK_PORT
#define IDC_JOYSTICK_LAST		IDC_JOYSTICK_CANCEL


/////////////////////////////////////////////////////////////////////////////
// Static objects

static DWORD s_dwStickIds[ MAX_ATARI_JOYPORTS ] =
{
	IDC_JOYSTICK_STICK1,
	IDC_JOYSTICK_STICK2,
	IDC_JOYSTICK_STICK3,
	IDC_JOYSTICK_STICK4
};

static DWORD s_dwAfireIds[ MAX_ATARI_JOYPORTS ] =
{
	IDC_JOYSTICK_AUTOFIRE1,
	IDC_JOYSTICK_AUTOFIRE2,
	IDC_JOYSTICK_AUTOFIRE3,
	IDC_JOYSTICK_AUTOFIRE4
};


/////////////////////////////////////////////////////////////////////////////
// CJoystickDlg dialog

BEGIN_MESSAGE_MAP(CJoystickDlg, CCommonDlg)
	//{{AFX_MSG_MAP(CJoystickDlg)
	ON_CBN_SELCHANGE(IDC_JOYSTICK_PORT, OnSelchangePort)
	ON_CBN_SELCHANGE(IDC_JOYSTICK_STICK1, OnSelchangeStick1)
	ON_CBN_SELCHANGE(IDC_JOYSTICK_STICK2, OnSelchangeStick2)
	ON_CBN_SELCHANGE(IDC_JOYSTICK_STICK3, OnSelchangeStick3)
	ON_CBN_SELCHANGE(IDC_JOYSTICK_STICK4, OnSelchangeStick4)
	ON_CBN_SELCHANGE(IDC_JOYSTICK_STICK, OnSelchangeStick)
	ON_CBN_SELCHANGE(IDC_JOYSTICK_AUTOFIREMODE, OnSelchangeAutofireMode)
	ON_BN_CLICKED(IDC_JOYSTICK_AUTOFIRE1, OnAutofire1)
	ON_BN_CLICKED(IDC_JOYSTICK_AUTOFIRE2, OnAutofire2)
	ON_BN_CLICKED(IDC_JOYSTICK_AUTOFIRE3, OnAutofire3)
	ON_BN_CLICKED(IDC_JOYSTICK_AUTOFIRE4, OnAutofire4)
	ON_BN_CLICKED(IDC_JOYSTICK_AUTOFIRE, OnAutofire)
	ON_BN_CLICKED(IDC_JOYSTICK_KEYSETA, OnKeysetA)
	ON_BN_CLICKED(IDC_JOYSTICK_KEYSETB, OnKeysetB)
	ON_BN_CLICKED(IDC_JOYSTICK_ADVSETTING, OnAdvSetting)
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_JOYSTICK_OK, OnOK)
	ON_BN_CLICKED(IDC_JOYSTICK_CANCEL, CCommonDlg::OnCancel)
END_MESSAGE_MAP()

/*========================================================
Method   : CJoystickDlg::CJoystickDlg
=========================================================*/
/* #FN#
   Standard constructor */
CJoystickDlg::
CJoystickDlg(
	CWnd *pParent /*=NULL*/
)
	: CCommonDlg( (g_Screen.ulState & SM_ATTR_SMALL_DLG ? IDD_JOYSTICK_SMALL : CJoystickDlg::IDD), pParent )
{
	//{{AFX_DATA_INIT(CJoystickDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT

	m_nFirstCtrl = IDC_JOYSTICK_FIRST;
	m_nLastCtrl  = IDC_JOYSTICK_LAST;
} /* #OF# CJoystickDlg::CJoystickDlg */

/*========================================================
Method   : CJoystickDlg::DoDataExchange
=========================================================*/
/* #FN#
   Dynamic Data Exchange (not used) */
void
/* #AS#
   Nothing */
CJoystickDlg::
DoDataExchange(
	CDataExchange *pDX /* #IN# Pointer to CDataExchange object */
)
{
	CCommonDlg::DoDataExchange( pDX );
	//{{AFX_DATA_MAP(CJoystickDlg)
		// NOTE: the ClassWizard will add DDX and DDV calls here
	//}}AFX_DATA_MAP
} /* #OF# CJoystickDlg::DoDataExchange */


/////////////////////////////////////////////////////////////////////////////
// CHarddiskDlg implementation

/*========================================================
Method   : CJoystickDlg::SetDlgState
=========================================================*/
/* #FN#
   Sets up the state of the dialog controls */
void
/* #AS#
   Nothing */
CJoystickDlg::
SetDlgState()
{
	CComboBox *pCombo  = NULL;
	CButton	  *pButton = NULL;
	char       szItem[ LOADSTRING_SIZE_S ];
	int i, j;

	for( i = 0; i < MAX_ATARI_JOYPORTS; i++ )
	{
		pCombo = (CComboBox *)GetDlgItem( m_bSmallMode ? IDC_JOYSTICK_STICK : s_dwStickIds[ i ] );
		ASSERT(pCombo);
		pCombo->ResetContent();

		/* Keyboard input */
		pCombo->AddString( _LoadStringSx( IDS_JOY_NUMPAD,   szItem ) );
		pCombo->AddString( _LoadStringSx( IDS_JOY_ARROWS,   szItem ) );
		pCombo->AddString( _LoadStringSx( IDS_JOY_KEYSET_A, szItem ) );
		pCombo->AddString( _LoadStringSx( IDS_JOY_KEYSET_B, szItem ) );

		/* Available input devices */
		for( j = 0; j < g_Input.nDevFoundNum; j++ )
			pCombo->AddString( g_Input.acDevNames[ j ] );

		/* No input device */
		pCombo->AddString( _LoadStringSx( IDS_JOY_NONE, szItem ) );

		if(	m_anDevSelected[ i ] != NO_JOYSTICK )
		{
			pCombo->SetCurSel( m_anDevSelected[ i ] + NUM_KBJOY_DEVICES );
		}
		else
			pCombo->SetCurSel( g_Input.nDevFoundNum + NUM_KBJOY_DEVICES );

		if( m_ulAutoSticks & (1 << i) )
		{
			pButton = (CButton *)GetDlgItem( m_bSmallMode ? IDC_JOYSTICK_AUTOFIRE : s_dwAfireIds[ i ] );
			ASSERT(pButton);
			pButton->SetCheck( TRUE );
		}
		if( m_bSmallMode )
		{
			pCombo = (CComboBox *)GetDlgItem( IDC_JOYSTICK_PORT );
			ASSERT(pCombo);
			pCombo->SetCurSel( 0 );

			/* There is one combo only in a small version of the window */
			break;
		}
	}
	pCombo = (CComboBox *)GetDlgItem( IDC_JOYSTICK_AUTOFIREMODE );
	ASSERT(pCombo);
	pCombo->SetCurSel( m_nAutoMode );
} /* #OF# CJoystickDlg::SetDlgState */


/////////////////////////////////////////////////////////////////////////////
// CJoystickDlg message handlers

/*========================================================
Method   : CJoystickDlg::OnInitDialog
=========================================================*/
/* #FN#
   Performs special processing when the dialog box is initialized */
BOOL
/* #AS#
   TRUE unless you set the focus to a control */
CJoystickDlg::
OnInitDialog()
{
	CCommonDlg::OnInitDialog();

	m_ulInputState   = g_Input.ulState;
	m_ulAutoSticks   = g_Input.Joy.ulAutoSticks;
	m_nAutoMode      = g_Input.Joy.nAutoMode;
	m_nBlockOpposite = joy_block_opposite_directions;

	m_bSmallMode = g_Screen.ulState & SM_ATTR_SMALL_DLG;

	for( int i = 0; i < MAX_ATARI_JOYPORTS; i++ )
		m_anDevSelected[ i ] = g_Input.anDevSelected[ i ];

	SetDlgState();

	return TRUE;  // return TRUE unless you set the focus to a control
				  // EXCEPTION: OCX Property Pages should return FALSE
} /* #OF# CJoystickDlg::OnInitDialog */

/*========================================================
Method   : CJoystickDlg::OnSelchangePort
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate combo box
   Small window mode */
void
/* #AS#
   Nothing */
CJoystickDlg::
OnSelchangePort()
{
	CComboBox *pStick  = (CComboBox *)GetDlgItem( IDC_JOYSTICK_STICK );
	CComboBox *pPort   = (CComboBox *)GetDlgItem( IDC_JOYSTICK_PORT );
	CButton   *pButton = (CButton *)GetDlgItem( IDC_JOYSTICK_AUTOFIRE );
	int	nStickNum = 0;

	ASSERT(pStick && pPort && pButton);

	if( (nStickNum = pPort->GetCurSel()) == CB_ERR )
		pPort->SetCurSel( 0 );

	if(	m_anDevSelected[ nStickNum ] != NO_JOYSTICK )
	{
		/* Set an appropriate device if any has been selected */
		pStick->SetCurSel( m_anDevSelected[ nStickNum ] + NUM_KBJOY_DEVICES );
	}
	else
		pStick->SetCurSel( g_Input.nDevFoundNum + NUM_KBJOY_DEVICES );

	pButton->SetCheck( (m_ulAutoSticks & (1 << nStickNum)) != 0 );
} /* #OF# CJoystickDlg::OnSelchangePort */

/*========================================================
Method   : CJoystickDlg::OnSelchangeStick
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate combo box.
   Small window mode */
void
/* #AS#
   Nothing */
CJoystickDlg::
OnSelchangeStick()
{
	CComboBox *pPort = NULL;
	int	nStickNum = 0;

	pPort = (CComboBox *)GetDlgItem( IDC_JOYSTICK_PORT );
	ASSERT(pPort);

	if( CB_ERR == (nStickNum = pPort->GetCurSel()) )
		pPort->SetCurSel( 0 );

	SelchangeStick( nStickNum );
} /* #OF# CJoystickDlg::OnSelchangeStick */

/*========================================================
Method   : CJoystickDlg::OnAutofire
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate combo box.
   Small window mode */
void
/* #AS#
   Nothing */
CJoystickDlg::
OnAutofire()
{
	CComboBox *pPort = NULL;
	int	nStickNum = 0;

	pPort = (CComboBox *)GetDlgItem( IDC_JOYSTICK_PORT );
	ASSERT(pPort);

	if( (nStickNum = pPort->GetCurSel()) == CB_ERR )
		pPort->SetCurSel( 0 );

	Autofire( nStickNum );
} /* #OF# CJoystickDlg::OnAutofire */

/*========================================================
Method   : CJoystickDlg::SelchangeStick
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate combo box */
void
/* #AS#
   Nothing */
CJoystickDlg::
SelchangeStick(
	int nStickNum
)
{
	CComboBox *pStick1 = (CComboBox *)GetDlgItem( m_bSmallMode ? IDC_JOYSTICK_STICK : s_dwStickIds[ nStickNum ] );
	CComboBox *pStick2 = NULL;
	int        nJoy;

	ASSERT(pStick1);

	/* Get the joystick selection */
	if( CB_ERR == (nJoy = pStick1->GetCurSel()) )
		return;

	if( nJoy <= g_Input.nDevFoundNum + NUM_KBJOY_DEVICES - 1  /* Zero based index */ )
	{
		nJoy -= NUM_KBJOY_DEVICES;

		for( int i = 0; i < MAX_ATARI_JOYPORTS; i++ )
		{
			if( (nJoy == m_anDevSelected[ i ]) && i != nStickNum )
			{
				if( IDYES == DisplayMessage( GetSafeHwnd(), IDS_WARN_STICK_CONFLICT, 0, MB_ICONQUESTION | MB_YESNO, i + 1, nStickNum + 1 ) )
				{
					if( !m_bSmallMode )
					{
						pStick2 = (CComboBox *)GetDlgItem( s_dwStickIds[ i ] );
						ASSERT(pStick2);
						pStick2->SetCurSel( g_Input.nDevFoundNum + NUM_KBJOY_DEVICES );
					}
					m_anDevSelected[ i ] = NO_JOYSTICK;
				}
				else
					nJoy = m_anDevSelected[ nStickNum ];

				/* There may be only one the same device associated
				   to a port, break */
				break;
			}
		}
	}
	else
		nJoy = NO_JOYSTICK;

	/* Set the selected device to use */
	m_anDevSelected[ nStickNum ] = nJoy;
	/* Synchronize a device combo box */
	pStick1->SetCurSel( (NO_JOYSTICK == nJoy ? g_Input.nDevFoundNum : nJoy) + NUM_KBJOY_DEVICES );
} /* #OF# CJoystickDlg::SelchangeStick */

/*========================================================
Method   : CJoystickDlg::OnSelchangeStick1
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate combo box */
void
/* #AS#
   Nothing */
CJoystickDlg::
OnSelchangeStick1()
{
	SelchangeStick( 0 );
} /* #OF# CJoystickDlg::OnSelchangeStick1 */

/*========================================================
Method   : CJoystickDlg::OnSelchangeStick2
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate combo box */
void
/* #AS#
   Nothing */
CJoystickDlg::
OnSelchangeStick2()
{
	SelchangeStick( 1 );
} /* #OF# CJoystickDlg::OnSelchangeStick2 */

/*========================================================
Method   : CJoystickDlg::OnSelchangeStick3
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate combo box */
void
/* #AS#
   Nothing */
CJoystickDlg::
OnSelchangeStick3()
{
	SelchangeStick( 2 );
} /* #OF# CJoystickDlg::OnSelchangeStick3 */

/*========================================================
Method   : CJoystickDlg::OnSelchangeStick4
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate combo box */
void
/* #AS#
   Nothing */
CJoystickDlg::
OnSelchangeStick4()
{
	SelchangeStick( 3 );
} /* #OF# CJoystickDlg::OnSelchangeStick4 */

/*========================================================
Method   : CJoystickDlg::Autofire
=========================================================*/
void
/* #AS#
   Nothing */
CJoystickDlg::
Autofire(
	int nStickNum
)
{
	_ClickButton( m_bSmallMode ? IDC_JOYSTICK_AUTOFIRE : s_dwAfireIds[ nStickNum ], m_ulAutoSticks, 1 << nStickNum );
} /* #OF# CJoystickDlg::Autofire */

/*========================================================
Method   : CJoystickDlg::OnAutofire1
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate check box */
void
/* #AS#
   Nothing */
CJoystickDlg::
OnAutofire1()
{
	Autofire( 0 );
} /* #OF# CJoystickDlg::OnAutofire1 */

/*========================================================
Method   : CJoystickDlg::OnAutofire2
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate check box */
void
/* #AS#
   Nothing */
CJoystickDlg::
OnAutofire2()
{
	Autofire( 1 );
} /* #OF# CJoystickDlg::OnAutofire2 */

/*========================================================
Method   : CJoystickDlg::OnAutofire3
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate check box */
void
/* #AS#
   Nothing */
CJoystickDlg::
OnAutofire3()
{
	Autofire( 2 );
} /* #OF# CJoystickDlg::OnAutofire3 */

/*========================================================
Method   : CJoystickDlg::OnAutofire4
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate check box */
void
/* #AS#
   Nothing */
CJoystickDlg::
OnAutofire4()
{
	Autofire( 3 );
} /* #OF# CJoystickDlg::OnAutofire4 */

/*========================================================
Method   : CJoystickDlg::OnSelchangeAutofireMode
=========================================================*/
/* #FN#
   Sets a state of the object regarding to an appropriate combo box */
void
/* #AS#
   Nothing */
CJoystickDlg::
OnSelchangeAutofireMode()
{
	CComboBox *pCombo = (CComboBox *)GetDlgItem( IDC_JOYSTICK_AUTOFIREMODE );
	ASSERT(pCombo != NULL);
	m_nAutoMode = pCombo->GetCurSel();
} /* #OF# CJoystickDlg::OnSelchangeAutofireMode */

/*========================================================
Method   : CJoystickDlg::OnKeysetA
=========================================================*/
/* #FN#
   Displays "Configure Keyset A" dialog box */
void
/* #AS#
   Nothing */
CJoystickDlg::
OnKeysetA()
{
	CKeysetDlg dlgKeyset;

	int nResult = IDOK;
	if( !(g_Misc.ulDontShow & DONT_SHOW_KBJOY_WARN) &&
		!(m_ulInputState & IS_JOY_DONT_EXCLUDE) )
	{
		CWarningDlg	dlgWarning;
		dlgWarning.m_nWarningID   = IDS_WARN_KBJOY;
		dlgWarning.m_nWarningFlag = DONT_SHOW_KBJOY_WARN;

		nResult = dlgWarning.DoModal();
	}
	if( nResult == IDOK )
	{
		dlgKeyset.SetTitlePostfix( " A" );
		dlgKeyset.SetCurrentKeyset( KEYS_A_JOYSTICK + NUM_KBJOY_DEVICES );
		dlgKeyset.DoModal();
	}
} /* #OF# CJoystickDlg::OnKeysetA */

/*========================================================
Method   : CJoystickDlg::OnKeysetB
=========================================================*/
/* #FN#
   Displays "Configure Keyset B" dialog box */
void
/* #AS#
   Nothing */
CJoystickDlg::
OnKeysetB()
{
	CKeysetDlg dlgKeyset;

	int nResult = IDOK;
	if( !(g_Misc.ulDontShow & DONT_SHOW_KBJOY_WARN) &&
		!(m_ulInputState & IS_JOY_DONT_EXCLUDE) )
	{
		CWarningDlg	dlgWarning;
		dlgWarning.m_nWarningID   = IDS_WARN_KBJOY;
		dlgWarning.m_nWarningFlag = DONT_SHOW_KBJOY_WARN;

		nResult = dlgWarning.DoModal();
	}
	if( nResult == IDOK )
	{
		dlgKeyset.SetTitlePostfix( " B" );
		dlgKeyset.SetCurrentKeyset( KEYS_B_JOYSTICK + NUM_KBJOY_DEVICES );
		dlgKeyset.DoModal();
	}
} /* #OF# CJoystickDlg::OnKeysetB */

/*========================================================
Method   : CJoystickDlg::OnAdvSetting
=========================================================*/
/* #FN#
   Displays "Advanced Joystick Options" dialog box */
void
/* #AS#
   Nothing */
CJoystickDlg::
OnAdvSetting()
{
	CJoystickAdvDlg dlgJoystickAdv( &m_ulInputState, &m_nBlockOpposite, this );

	dlgJoystickAdv.DoModal();
} /* #OF# CSettingsDlg::OnAdvSetting */

/*========================================================
Method   : CJoystickDlg::OnOK
=========================================================*/
/* #FN#
   Called when the user clicks the OK button */
void
/* #AS#
   Nothing */
CJoystickDlg::
OnOK()
{
	BOOL bChanged = FALSE;

	if( m_ulInputState != g_Input.ulState )
	{
		g_Input.ulState = m_ulInputState;
		WriteRegDWORD( NULL, REG_INPUT_STATE, g_Input.ulState );
	}
	if( m_nAutoMode != g_Input.Joy.nAutoMode )
	{
		g_Input.Joy.nAutoMode = m_nAutoMode;
		WriteRegDWORD( NULL, REG_AUTOFIRE_MODE, g_Input.Joy.nAutoMode );

		/* Update main window's indicator */
		UpdateIndicator( ID_INDICATOR_JOY );
	}
	if( m_ulAutoSticks != g_Input.Joy.ulAutoSticks )
	{
		g_Input.Joy.ulAutoSticks = m_ulAutoSticks;
		WriteRegDWORD( NULL, REG_AUTOFIRE_STICKS, g_Input.Joy.ulAutoSticks );
	}
	if( m_nBlockOpposite != joy_block_opposite_directions )
	{
		joy_block_opposite_directions = m_nBlockOpposite;
		WriteRegDWORD( NULL, REG_BLOCK_OPPOSITE, joy_block_opposite_directions );
	}

	for( int i = 0; i < MAX_ATARI_JOYPORTS; i++ )
	{
		if( m_anDevSelected[ i ] != g_Input.anDevSelected[ i ] )
			bChanged = TRUE;
	}
	if( bChanged )
	{
		g_Input.Joy.ulSelected  = (ULONG)((UBYTE)m_anDevSelected[ 3 ]) << 24;
		g_Input.Joy.ulSelected |= (ULONG)((UBYTE)m_anDevSelected[ 2 ]) << 16;
		g_Input.Joy.ulSelected |= (ULONG)((UBYTE)m_anDevSelected[ 1 ]) << 8;
		g_Input.Joy.ulSelected |= (ULONG)((UBYTE)m_anDevSelected[ 0 ]);

		WriteRegDWORD( NULL, REG_JOYSTICKS, g_Input.Joy.ulSelected );
	}
	Input_Initialise( bChanged );

	CCommonDlg::OnOK();
} /* #OF# CJoystickDlg::OnOK */
