/****************************************************************************
File    : Helpers.cpp
/*
@(#) #SY# Atari800Win PLus
@(#) #IS# Implementation of usefull methods and objects
@(#) #BY# Tomasz Szymankowski
@(#) #LM# 14.03.2002
*/

#include "StdAfx.h"
#include "Atari800Win.h"
#include "MainFrame.h"
#include "FileSmallDlg.h"
#include "RomTypeDlg.h"
#include "Helpers.h"


/////////////////////////////////////////////////////////////////////////////
//
//   C++ stuff implementation
//

BOOL g_bLargeFonts = LOWORD(GetDialogBaseUnits()) >= 10;


/////////////////////////////////////////////////////////////////////////////
// File management

/*========================================================
Function : PickFileName
=========================================================*/
/* #FN#
   Displays file dialog and ask user for a file name */
BOOL
/* #AS#
   TRUE if the file was picked, otherwise FALSE */
PickFileName(
	BOOL    bOpenFileDialog,		 /* #IN# */
	LPSTR   pszFileName,			 /* #IN/OUT# */
	LPCSTR  pszPrompt,				 /* #IN# */
	LPCSTR  pszFilter,				 /* #IN# */
	LPCSTR  pszDefExt,				 /* #IN# */
	DWORD   dwFlags,				 /* #IN# */
	BOOL    bCheckPath  /*=TRUE*/,   /* #IN# */
	LPCSTR  pszNoneFile /*="None"*/, /* #IN# */
	CWnd   *pParentWnd  /*=NULL*/    /* #IN# */
)
{
	char szFilePath[ MAX_PATH ];
	int  nResult = IDOK;

	strncpy( szFilePath, pszFileName, MAX_PATH );
	szFilePath[ MAX_PATH - 1 ] = '\0';

	if( bCheckPath )
	{
		CFileStatus fsStatus;
		int i;

		/* Standard FileDialog wants that */
		do
		{
			/* Remove the ending backslash */
			for( i = strlen( szFilePath ) - 1; i >= 0 && szFilePath[ i ] == '\\'; i-- )
				szFilePath[ i ] = '\0';
			/* We have got a drive here, don't process */
			if( strlen( szFilePath ) == 2 && szFilePath[ 1 ] == ':' )
			{
				strcat( szFilePath, "\\" );
				strcat( szFilePath, pszNoneFile );
				break;
			}
			/* That's the static method, don't panic */
			if( CFile::GetStatus( szFilePath, fsStatus ) )
			{
				if( fsStatus.m_attribute & CFile::directory )
				{
					strcat( szFilePath, "\\" );
					strcat( szFilePath, pszNoneFile );
				}
				break;
			}
			else
			{
				for( i = strlen( szFilePath );
					 i >= 0 && szFilePath[ i ] != '\\'; i-- )
					szFilePath[ i ] = '\0';
			}
		}
		while( i > 0 );
	}
	if( *szFilePath == '\0' )
		strcpy( szFilePath, pszNoneFile );

	/* Open the file dialog */
	_CursorBusy();
	if( g_Screen.ulState & SM_ATTR_SMALL_DLG )
	{
		CFileSmallDlg dlgFileSmall( bOpenFileDialog,
									pszDefExt,
									pszPrompt,
									szFilePath,
									FALSE,
									(pParentWnd ? pParentWnd : AfxGetMainWnd()) );

		if( IDOK == (nResult = dlgFileSmall.DoModal()) )
			strncpy( pszFileName, dlgFileSmall.GetPathName(), MAX_PATH );
	}
	else
	{
		if( g_Screen.ulState & SM_MODE_FULL )
			dwFlags |= OFN_ENABLEHOOK;

		CFileDialog	fdlgFile( bOpenFileDialog,
							  pszDefExt,
							  szFilePath,
							  dwFlags,
							  pszFilter,
							  (pParentWnd ? pParentWnd : AfxGetMainWnd()) );

		fdlgFile.m_ofn.lpstrTitle = pszPrompt;
		if( g_Screen.ulState & SM_MODE_FULL )
			fdlgFile.m_ofn.lpfnHook = FileDialogHookProc;

		if( IDOK == (nResult = fdlgFile.DoModal()) )
			strncpy( pszFileName, fdlgFile.GetPathName(), MAX_PATH );
	}
	_CursorFree();

	return (nResult == IDOK ? TRUE : FALSE);
} /* #OF# PickFileName */

/*========================================================
Function : PickFileName
=========================================================*/
/* #FN#
   Displays file dialog and ask user for a file name */
BOOL
/* #AS#
   TRUE if the file was picked, otherwise FALSE */
PickFileName(
	BOOL     bOpenFileDialog,		  /* #IN# */
	LPSTR    pszFileName,			  /* #IN/OUT# */
	LPCSTR   pszPrompt,				  /* #IN# */
	UINT     nFilterID,				  /* #IN# */
	LPCSTR   pszDefExt,				  /* #IN# */
	DWORD    dwFlags,				  /* #IN# */
	BOOL     bCheckPath  /*=TRUE*/,   /* #IN# */
	LPCSTR   pszNoneFile /*="None"*/, /* #IN# */
	CWnd    *pParentWnd  /*=NULL*/    /* #IN# */
)
{
	char szFilter[ LOADSTRING_SIZE_M ];

	BOOL bResult =
		PickFileName( bOpenFileDialog,
					  pszFileName,
					  pszPrompt,
					  _LoadStringMx( nFilterID, szFilter ),
					  pszDefExt,
					  dwFlags,
					  bCheckPath,
					  pszNoneFile,
					  pParentWnd );

	return bResult;
} /* #OF# PickFileName */

/*========================================================
Function : PickFileName
=========================================================*/
/* #FN#
   Displays file dialog and ask user for a file name */
BOOL
/* #AS#
   TRUE if the file was picked, otherwise FALSE */
PickFileName(
	BOOL     bOpenFileDialog,		  /* #IN# */
	LPSTR    pszFileName,			  /* #IN/OUT# */
	UINT     nPromptID,				  /* #IN# */
	LPCSTR   pszFilter,				  /* #IN# */
	LPCSTR   pszDefExt,				  /* #IN# */
	DWORD    dwFlags,				  /* #IN# */
	BOOL     bCheckPath  /*=TRUE*/,   /* #IN# */
	LPCSTR   pszNoneFile /*="None"*/, /* #IN# */
	CWnd    *pParentWnd  /*=NULL*/    /* #IN# */
)
{
	char szPrompt[ LOADSTRING_SIZE_S ];

	BOOL bResult =
		PickFileName( bOpenFileDialog,
					  pszFileName,
					  _LoadStringSx( nPromptID, szPrompt ),
					  pszFilter,
					  pszDefExt,
					  dwFlags,
					  bCheckPath,
					  pszNoneFile,
					  pParentWnd );

	return bResult;
} /* #OF# PickFileName */

/*========================================================
Function : PickFileName
=========================================================*/
/* #FN#
   Displays file dialog and ask user for a file name */
BOOL
/* #AS#
   TRUE if the file was picked, otherwise FALSE */
PickFileName(
	BOOL     bOpenFileDialog,		  /* #IN# */
	LPSTR    pszFileName,			  /* #IN/OUT# */
	UINT     nPromptID,				  /* #IN# */
	UINT     nFilterID,				  /* #IN# */
	LPCSTR   pszDefExt,				  /* #IN# */
	DWORD    dwFlags,				  /* #IN# */
	BOOL     bCheckPath  /*=TRUE*/,   /* #IN# */
	LPCSTR   pszNoneFile /*="None"*/, /* #IN# */
	CWnd    *pParentWnd  /*=NULL*/    /* #IN# */
)
{
	char szPrompt[ LOADSTRING_SIZE_S ];
	char szFilter[ LOADSTRING_SIZE_M ];

	BOOL bResult =
		PickFileName( bOpenFileDialog,
					  pszFileName,
					  _LoadStringSx( nPromptID, szPrompt ),
					  _LoadStringMx( nFilterID, szFilter ),
					  pszDefExt,
					  dwFlags,
					  bCheckPath,
					  pszNoneFile,
					  pParentWnd );

	return bResult;
} /* #OF# PickFileName */

/*========================================================
Function : PickFileName
=========================================================*/
/* #FN#
   Displays file dialog and ask user for a file name */
BOOL
/* #AS#
   TRUE if the file was picked, otherwise FALSE */
PickFileName(
	BOOL     bOpenFileDialog,		  /* #IN# */
	CString &strFileName,			  /* #IN/OUT# */
	LPCSTR   pszPrompt,				  /* #IN# */
	LPCSTR   pszFilter,				  /* #IN# */
	LPCSTR   pszDefExt,				  /* #IN# */
	DWORD    dwFlags,				  /* #IN# */
	BOOL     bCheckPath  /*=TRUE*/,   /* #IN# */
	LPCSTR   pszNoneFile /*="None"*/, /* #IN# */
	CWnd    *pParentWnd  /*=NULL*/    /* #IN# */
)
{
	BOOL bResult =
		PickFileName( bOpenFileDialog,
					  strFileName.GetBuffer( MAX_PATH ),
					  pszPrompt,
					  pszFilter,
					  pszDefExt,
					  dwFlags,
					  bCheckPath,
					  pszNoneFile,
					  pParentWnd );

	strFileName.ReleaseBuffer();

	return bResult;
} /* #OF# PickFileName */

/*========================================================
Function : PickFileName
=========================================================*/
/* #FN#
   Displays file dialog and ask user for a file name */
BOOL
/* #AS#
   TRUE if the file was picked, otherwise FALSE */
PickFileName(
	BOOL     bOpenFileDialog,		  /* #IN# */
	CString &strFileName,			  /* #IN/OUT# */
	LPCSTR   pszPrompt,				  /* #IN# */
	UINT     nFilterID,				  /* #IN# */
	LPCSTR   pszDefExt,				  /* #IN# */
	DWORD    dwFlags,				  /* #IN# */
	BOOL     bCheckPath  /*=TRUE*/,   /* #IN# */
	LPCSTR   pszNoneFile /*="None"*/, /* #IN# */
	CWnd    *pParentWnd  /*=NULL*/    /* #IN# */
)
{
	char szFilter[ LOADSTRING_SIZE_M ];

	BOOL bResult =
		PickFileName( bOpenFileDialog,
					  strFileName.GetBuffer( MAX_PATH ),
					  pszPrompt,
					  _LoadStringMx( nFilterID, szFilter ),
					  pszDefExt,
					  dwFlags,
					  bCheckPath,
					  pszNoneFile,
					  pParentWnd );

	strFileName.ReleaseBuffer();

	return bResult;
} /* #OF# PickFileName */

/*========================================================
Function : PickFileName
=========================================================*/
/* #FN#
   Displays file dialog and ask user for a file name */
BOOL
/* #AS#
   TRUE if the file was picked, otherwise FALSE */
PickFileName(
	BOOL     bOpenFileDialog,		  /* #IN# */
	CString &strFileName,			  /* #IN/OUT# */
	UINT     nPromptID,				  /* #IN# */
	LPCSTR   pszFilter,				  /* #IN# */
	LPCSTR   pszDefExt,				  /* #IN# */
	DWORD    dwFlags,				  /* #IN# */
	BOOL     bCheckPath  /*=TRUE*/,   /* #IN# */
	LPCSTR   pszNoneFile /*="None"*/, /* #IN# */
	CWnd    *pParentWnd  /*=NULL*/    /* #IN# */
)
{
	char szPrompt[ LOADSTRING_SIZE_S ];

	BOOL bResult =
		PickFileName( bOpenFileDialog,
					  strFileName.GetBuffer( MAX_PATH ),
					  _LoadStringSx( nPromptID, szPrompt ),
					  pszFilter,
					  pszDefExt,
					  dwFlags,
					  bCheckPath,
					  pszNoneFile,
					  pParentWnd );

	strFileName.ReleaseBuffer();

	return bResult;
} /* #OF# PickFileName */

/*========================================================
Function : PickFileName
=========================================================*/
/* #FN#
   Displays file dialog and ask user for a file name */
BOOL
/* #AS#
   TRUE if the file was picked, otherwise FALSE */
PickFileName(
	BOOL     bOpenFileDialog,		  /* #IN# */
	CString &strFileName,			  /* #IN/OUT# */
	UINT     nPromptID,				  /* #IN# */
	UINT     nFilterID,				  /* #IN# */
	LPCSTR   pszDefExt,				  /* #IN# */
	DWORD    dwFlags,				  /* #IN# */
	BOOL     bCheckPath  /*=TRUE*/,   /* #IN# */
	LPCSTR   pszNoneFile /*="None"*/, /* #IN# */
	CWnd    *pParentWnd  /*=NULL*/    /* #IN# */
)
{
	char szPrompt[ LOADSTRING_SIZE_S ];
	char szFilter[ LOADSTRING_SIZE_M ];

	BOOL bResult =
		PickFileName( bOpenFileDialog,
					  strFileName.GetBuffer( MAX_PATH ),
					  _LoadStringSx( nPromptID, szPrompt ),
					  _LoadStringMx( nFilterID, szFilter ),
					  pszDefExt,
					  dwFlags,
					  bCheckPath,
					  pszNoneFile,
					  pParentWnd );

	strFileName.ReleaseBuffer();

	return bResult;
} /* #OF# PickFileName */


/////////////////////////////////////////////////////////////////////////////
// Cartridge management

/*========================================================
Function : PickCartridge
=========================================================*/
/* #FN#
   Displays file dialog and ask user for cartridge */
BOOL
/* #AS#
   TRUE if the cartridge was picked, otherwise FALSE */
PickCartridge(
	LPSTR pszCurrentCart,
	CWnd *pParentWnd /*=NULL*/
)
{
	BOOL bResult = FALSE;

	if( PickFileName( TRUE, pszCurrentCart, IDS_SELECT_ROM_LOAD, IDS_FILTER_CRT,
					  "rom", PF_LOAD_FLAGS, TRUE, "None", pParentWnd ) &&
		*pszCurrentCart != '\0' )
	{
		bResult = TRUE;
	}
	return bResult;
} /* #OF# PickCartridge */

/*========================================================
Function : AttachCartridge
=========================================================*/
/* #FN#
   Attaches cartridge */
int
/* #AS#
   Type of an attached cartridge, otherwise CART_NONE */
AttachCartridge(
	LPSTR pszCartridge
)
{
	int nCartType = CART_NONE;

	int nCartSize = CART_Insert( pszCartridge );
	if( nCartSize < 0 )
	{
		char szError[ LOADSTRING_SIZE_S ];
		/* If there was an error... */
		DisplayMessage( NULL, IDS_ERROR_ROM_LOAD, 0, MB_ICONEXCLAMATION | MB_OK,
						pszCartridge,
						nCartSize == CART_CANT_OPEN    ? _LoadStringSx( IDS_ERROR_CANT_OPEN, szError ) :
						nCartSize == CART_BAD_FORMAT   ? _LoadStringSx( IDS_ERROR_BAD_FORMAT, szError ) :
						nCartSize == CART_BAD_CHECKSUM ? _LoadStringSx( IDS_ERROR_BAD_CHECKSUM, szError ) :
						_LoadStringSx( IDS_ERROR_UNKNOWN, szError ) );
	}
	else if( nCartSize > 0 )
	{
		cart_type = SelectCartType( nCartSize );
		if( CART_NONE != cart_type )
		{
			CART_Start();
			strcpy( g_szCurrentRom, pszCartridge );

			nCartType = cart_type;
		}
	}
	else if( nCartSize == 0 )
	{
		strcpy( g_szCurrentRom, pszCartridge );
		nCartType = cart_type;
	}
	if( CART_NONE == nCartType )
	{
		CART_Remove();
		strcpy( g_szCurrentRom, "None" );
	}
	return nCartType;
} /* #OF# AttachCartridge */


/////////////////////////////////////////////////////////////////////////////
// Miscellanous

/*========================================================
Function : RestartEmulation
=========================================================*/
/* #FN#
   Restarts the emulator (kernel and Windows stuff) */
void
/* #AS#
   Nothing */
RestartEmulation(
	BOOL bForceWinInit /*=TRUE*/,
	BOOL bIgnoreParams /*=TRUE*/
)
{
	int argc = bIgnoreParams ? 1 : g_argc;
	/* Backup an Atari state flags */
	ULONG ulAtariState = g_ulAtariState;

	SIO_Exit();

	/* Reinitialise an emulator kernel */
	Atari800_Initialise( &argc,	bIgnoreParams ? NULL : g_argv );

	if( bForceWinInit ||
		/* Drag&Drop: don't worry about loosing the focus,
		   the emulated Atari won't start in this case */
		g_ulAtariState & ATARI_UNINITIALIZED )
	{
		ASSERT(g_hMainWnd);

		CMainFrame *pMainFrame = (CMainFrame *)AfxGetMainWnd();//::FromHandle( g_hMainWnd );
		ASSERT(pMainFrame);

		RECT rc;
		pMainFrame->GetClientRect( &rc );
		rc.left = rc.right / 2; rc.right = rc.left + 1;
		rc.top = rc.bottom / 2; rc.bottom = rc.top + 1;

		/* Clear the screen content */
		pMainFrame->CleanScreen();

		g_hViewWnd = NULL;
		/* Reinitialise Windows stuff */
		pMainFrame->RedrawWindow( &rc, NULL, RDW_INVALIDATE /*RDW_NOFRAME | RDW_NOERASE | RDW_UPDATENOW*/ );
	}
	else
	{
		g_ulAtariState = ulAtariState;
		/* Restart sound if necessary */
		Sound_Restart();
	}
} /* #OF# RestartEmulation */

/*========================================================
Function : FileDialogHookProc
=========================================================*/
/* #FN#
   Callback function used with the Explorer-style Open and Save As dialog boxes */
UINT CALLBACK
/* #AS#
   If zero, the default dialog box procedure processes the message */
FileDialogHookProc(
	HWND   hDlg,   /* #IN# Handle to child dialog window    */
	UINT   uMsg,   /* #IN# WM_NOTIFY                        */
	WPARAM wParam, /* #IN# Not used                         */
	LPARAM lParam  /* #IN# Message information (LPOFNOTIFY) */
)
{
	LPNMHDR lpNMHDR = (LPNMHDR)lParam;

	if( WM_NOTIFY == uMsg && lpNMHDR && CDN_INITDONE == lpNMHDR->code )
	{
		CWnd *pWnd = pWnd->FromHandle( lpNMHDR->hwndFrom );
		ASSERT(pWnd);

		SetWindowLong( lpNMHDR->hwndFrom, GWL_EXSTYLE, ~WS_EX_CONTEXTHELP & GetWindowLong( lpNMHDR->hwndFrom, GWL_EXSTYLE ) );
		pWnd->CenterWindow();

		return 1;
	}
	return 0;
} /* #OF# FileDialogHookProc */


/////////////////////////////////////////////////////////////////////////////
//
// Common stuff implementation
//

extern "C" { /* Do not decorate the function name, please */

/*========================================================
Function : InitialiseMachine
=========================================================*/
/* #FN#
   Initialises an emulated machine */
BOOL
/* #AS#
   Non zero if succeeded, otherwise zero */
InitialiseMachine( void )
{
	BOOL bResult = TRUE;

	/* Turn the cheat mode off */
	ResetCheatServer();

	if( !Atari800_InitialiseMachine() )
	{
		Aprint( "Failed loading specified Atari OS ROM or BASIC!\r\n"
				"Check filename under the 'Atari/ROM images' menu." );

		g_ulAtariState |= ATARI_LOAD_FAILED;

		if( g_hViewWnd )
			InvalidateRect( g_hViewWnd, NULL, FALSE );

		bResult = FALSE;
	}
	/* We also have to initialize R: device (not used by kernel) */
	RDevice_UpdatePatches();

	return bResult;
} /* #OF# InitialiseMachine */

/*========================================================
Function : SelectCartType
=========================================================*/
/* #FN#
   Recognizes a cartridge type */
int
/* #AS#
   Cartridge type */
SelectCartType(
	int nCartSize
)
{
	int nResult = CART_NONE;
	int nTypes  = 0;

	CRomTypeDlg dlgRomType( nCartSize );

	nTypes = dlgRomType.CountTypes( nCartSize );
	if( nTypes > 0 )
		if( 1 == nTypes || IDOK == dlgRomType.DoModal() )
		{
			nResult = dlgRomType.GetRomType();
		}
	return nResult;
} /* #OF# SelectCartType */

/*========================================================
Function : UpdateIndicator
=========================================================*/
/* #FN#
   Redraws the pointed icon on the status bar */
void
/* #AS#
   Nothing */
UpdateIndicator(
	int nPane
)
{
	CMainFrame *pMainFrame = (CMainFrame *)AfxGetMainWnd();
	ASSERT(pMainFrame);

	/* Update the given indicator */
	if( pMainFrame )
		pMainFrame->UpdateIndicator( nPane );
} /* #OF# UpdateIndicator */

/*========================================================
Function : UpdateStatus
=========================================================*/
/* #FN#
   Refreshes descriptions on the caption/status bar */
void
/* #AS#
   Nothing */
UpdateStatus(
	BOOL bForceShow,
	int  nSpeed,
	int  nPane,
	BOOL bWinMode
)
{
	CMainFrame *pMainFrame = (CMainFrame *)AfxGetMainWnd();
	ASSERT(pMainFrame);

	/* Update descriptions on the caption/status bar */
	if( pMainFrame )
		pMainFrame->UpdateStatus( bForceShow, nSpeed, nPane, bWinMode );
} /* #OF# UpdateStatus */

/*========================================================
Function : ResetLoopCounter
=========================================================*/
/* #FN#
   Resets emulator speed-calculation counters */
void
/* #AS#
   Nothing */
ResetLoopCounter(
	BOOL bSetSpeed
)
{
	CAtari800WinApp *pMainApp = (CAtari800WinApp *)AfxGetApp();
	ASSERT(pMainApp);

	/* Update descriptions on the caption/status bar */
	if( pMainApp )
		pMainApp->ResetLoopCounter( bSetSpeed );
} /* #OF# ResetLoopCounter */

/*========================================================
Function : LoadStringEx
=========================================================*/
/* #FN#
   Loads a string from resources basing on a given string ID */
char*
/* #AS#
   Pointer to a passed output buffer */
LoadStringEx(
	UINT  nStringID,
	char *pszBuffer,
	int   nBufLen
)
{
	if( NULL != pszBuffer )
	{
		if( !LoadString( NULL, nStringID, pszBuffer, nBufLen ) )
			strcpy( pszBuffer, "?" );
	}
	return pszBuffer;
} /* #OF# LoadStringEx */

/*========================================================
Function : ResetCheatServer
=========================================================*/
/* #FN#
   Resets the cheat server internal state */
void
/* #AS#
   Nothing */
ResetCheatServer()
{
	CAtari800WinApp *pMainApp = (CAtari800WinApp *)AfxGetApp();
	ASSERT(pMainApp);

	/* Update descriptions on the caption/status bar */
	if( pMainApp )
	{
		CCheatServer *pCheatServer = pMainApp->GetCheatServer();
		if( pCheatServer )
			pCheatServer->ResetState();
	}
} /* #OF# ResetCheatServer */

} //extern "C"
