/*
Copyright (c) 1998 Richard Lawrence

This program is free software; you can redistribute it and/or modify it under the terms 
of the GNU General Public License as published by the Free Software Foundation; either 
version 2 of the License, or (at your option) any later version. This program is 
distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details. You should have received a copy of the GNU
General Public License along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

// MainFrm.cpp : implementation of the CMainFrame class
//

#include "stdafx.h"
#include "Atari800Win.h"

#include "MainFrm.h"
#include "CDriveDialog.h"
#include "CHardwareDlg.h"
#include "CCartridgeDlg.h"
#include "CGraphicsDlg.h"
#include "CDriveSmallDlg.h"
#include "CGraphicsSmallDlg.h"
#include "CSoundDlg.h"
#include "CFileSmallDlg.h"
#include "CHardDiskDlg.h"
#include "CJoyStickDlg.h"
#include "CErrorLogDlg.h"
#include "CKeyBoard.h"
#include "CWarnDlg.h"
#include "resource.h"

#include "winatari.h"
#include "mmsystem.h"
#include "ddraw.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

extern "C" {
#include "atari.h"
#include "registry.h"
#include "graphics.h"
#include "statesav.h"
#include "sio.h"
extern int	nStatusSize;
extern int	nStartX, nStartY;
extern void Screen_Benchmark(void);
extern void Screen_Clear(void);
extern int ReadJoystickInput( int sticknum, BOOL bButton );
extern void art_main_init(int init_flag, int mode);
extern void Restart_Sound( void );
extern void Toggle_FullSpeed( void );
extern void Toggle_Pause( void );
extern void Toggle_SIO_Patch( void );
extern void ComputeClipArea( void );
extern void Screen_Paused( UBYTE *screen );
extern int zlib_capable( void );
extern void Atari_ReInit( void );
extern int ReadAtariExe( char *filename );
extern void DescribeAtariSystem( void );
extern BOOL dcmtoatr(FILE *fin, FILE *fout, char *input, char *output);
extern ULONG	ulDontShowFlags;
extern int	default_tv_mode;
extern FILE *sndoutput;
extern ULONG	ulMiscStates;
extern ULONG ulSoundState;
extern void Pokey_process (unsigned char *buffer, int n);
extern TCHAR	gcErrorString[];
extern HWND				hWnd, MainhWnd;
extern void DeleteAllRegKeys( HKEY hkInput, char *name );
extern int main (int argc, char **argv);
extern  ULONG	ulAtariState;
extern void WinAtari800_Hardware( void );
extern int	nSoundRate;
extern int Init_Graphics( void );
extern ULONG ulScreenMode;
extern int SHIFT_KEY, KEYPRESSED;
extern int		CTRL_KEY;
extern int		iNewKey;
extern int		iNewVK;
extern int		iCurrentKey;
extern int		iCurrentVK;
extern int	iKBTable[];
extern BOOL ToggleKeyDown( WPARAM wp );
extern BOOL ToggleKeyUp( WPARAM wp );
extern void BuildCRCTable(void);
extern int global_artif_mode;
}
//Mainframe needs this to pause/restart the Atari thread with F9

#ifdef ATARI_UI
extern BOOL	startThread( void );
#endif

extern unsigned char ucKeysCovered[];

CWnd	*statusWnd;

int		argc;
char	*argv[32];
char	szCmdLine[ 1024 ];

#include "win_keycodes.h"
/////////////////////////////////////////////////////////////////////////////
// CMainFrame


IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
	//{{AFX_MSG_MAP(CMainFrame)
	ON_WM_CREATE()
	ON_COMMAND(ID_ATARI_DISK, OnSystemDisk)
	ON_COMMAND(ID_ATARI_HARDWARE, OnAtariHardware)
	ON_COMMAND(ID_ATARI_CARTRIDGE, OnAtariCartridge)
	ON_WM_CLOSE()
	ON_COMMAND(ID_INFO_BENCHMARK, OnInfoBenchmark)
	ON_COMMAND(ID_OPTIONS_GRAPHICS, OnOptionsGraphics)
	ON_COMMAND(ID_OPTIONS_SOUND, OnOptionsSound)
	ON_COMMAND(ID_INFO_SOUND_POKEY_SPEED, OnInfoSoundPokeySpeed)
	ON_COMMAND(ID_ATARI_HARDDISK, OnAtariHarddisk)
	ON_COMMAND(ID_OPTIONS_JOYSTICK, OnOptionsJoystick)
	ON_COMMAND(ID_OPTIONS_LOG, OnOptionsLog)
	ON_COMMAND(ID_OPTIONS_SOUNDFILE, OnOptionsSoundfile)
	ON_WM_MOVE()
	ON_COMMAND(ID_MISC_CLEARALL, OnMiscClearall)
	ON_WM_TIMER()
	ON_COMMAND(ID_FILE_DCMTOATR, OnFileDcmtoatr)
	ON_COMMAND(ID_ATARI_REBOOT, OnAtariReboot)
	ON_COMMAND(ID_FILE_READSTATE, OnFileReadstate)
	ON_COMMAND(ID_FILE_SAVESTATE, OnFileSavestate)
	ON_COMMAND(ID_FILE_SAVESTATEROMS, OnFileSavestateroms)
	ON_COMMAND(ID_OPTIONS_KEYBOARD, OnOptionsKeyboard)
	ON_COMMAND(ID_ATAR_LOADEXE, OnAtarLoadexe)
	ON_COMMAND(ID_OPTIONS_ARTIF, OnOptionsArtif)
	//}}AFX_MSG_MAP
	// Global help commands
	ON_COMMAND(ID_HELP_FINDER, CFrameWnd::OnHelpFinder)
	ON_COMMAND(ID_HELP, CFrameWnd::OnHelp)
	ON_COMMAND(ID_CONTEXT_HELP, CFrameWnd::OnContextHelp)
	ON_COMMAND(ID_DEFAULT_HELP, CFrameWnd::OnHelpFinder)
END_MESSAGE_MAP()

static UINT indicators[] =
{
	ID_SEPARATOR//,           // status line indicator
//	ID_INDICATOR_SPEED,
//	ID_INDICATOR_CAPS,
//	ID_INDICATOR_NUM,
//	ID_INDICATOR_SCRL,
};

/////////////////////////////////////////////////////////////////////////////
// CMainFrame construction/destruction

CMainFrame::CMainFrame()
{
	// TODO: add member initialization code here
	iToolBar = 30;

	BuildCRCTable();

	HandleRegistry();
	if( ulMiscStates & ATARI_LAST_BOOT_FAILED )
	{
		int result;

		LoadString( NULL, IDS_LOCKUP_WARNING, gcErrorString, LOADSTRING_STRING_SIZE );
		result = MessageBox( gcErrorString, "Atari800Win", MB_YESNO );
		if( result == IDYES )
		{
			ulScreenMode = DISPLAY_MODE_DEFAULT | DDRAW_NONE;
			ulSoundState = SOUND_NOSOUND;
			WriteInitialReg( NULL, TRUE );
		}
		ulMiscStates &= ~ATARI_LAST_BOOT_FAILED;
	}
	main( argc, &argv[0] );
}

CMainFrame::~CMainFrame()
{
	//In case desktop isn't getting refreshed when exiting directly from DirectDraw full screen
	::InvalidateRect( NULL, NULL, FALSE );
}

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
#ifdef USE_PERF_COUNTER
	LARGE_INTEGER	lnTimerRes;

	QueryPerformanceFrequency( &lnTimerRes ); 
	ASSERT( lnTimerRes.HighPart == 0 );
	if( lnTimerRes.LowPart == 0 )
	{
		LoadString( NULL, IDS_NO_HIRES_TIMER, gcErrorString, LOADSTRING_STRING_SIZE );
		MessageBox( gcErrorString, NULL, MB_OK );
		return FALSE;
	}
#endif

	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	if (!m_wndStatusBar.Create(this) ||
		!m_wndStatusBar.SetIndicators(indicators,
		  sizeof(indicators)/sizeof(UINT)))
	{
		TRACE0("Failed to create status bar\n");
		return -1;      // fail to create
	}

	statusWnd = (CWnd *)&m_wndStatusBar;
	
	CClientDC	cdcStatus( statusWnd );
	CSize		size;
	size = cdcStatus.GetTextExtent( "Test" );
	nStatusSize =size.cy + GetSystemMetrics( SM_CYBORDER )*2;

	// TODO: Remove this if you don't want tool tips or a resizeable toolbar
//	m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
//		CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);

	// TODO: Delete these three lines if you don't want the toolbar to
	//  be dockable
//	m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
//	EnableDocking(CBRS_ALIGN_ANY);
//	DockControlBar(&m_wndToolBar);

	return 0;
}

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
	cs.x = nStartX;
	cs.y = nStartY;

//	cs.style |= FWS_ADDTOTITLE;
//	cs.style |= CS_CLASSDC;
//	cs.style |= CS_PARENTDC;
//	cs.style |= CS_BYTEALIGNCLIENT;
	cs.style &= ~WS_THICKFRAME;
	//cs.style |= CS_BYTEALIGNWINDOW;
	cs.style |= CS_OWNDC;

	return CFrameWnd::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CMainFrame diagnostics

#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
	CFrameWnd::AssertValid();
}

void CMainFrame::Dump(CDumpContext& dc) const
{
	CFrameWnd::Dump(dc);
}

#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CMainFrame message handlers

void CMainFrame::DriveInsert( int drivenum )
{
	CString	name = "";
	char	szCurDir[ MAX_PATH ];
	char	szPrompt[128];
	char	szNewDir[ MAX_PATH ];

	sprintf( szPrompt, "Select disk to insert in drive %d", drivenum );
	GetCurrentDirectory( MAX_PATH, szCurDir );

	ReadRegBinary( NULL, szDriveRegID[ drivenum - 1 ], &szNewDir[0], MAX_PATH, FALSE );
	if( strcmp( szNewDir, "Empty" ) && strcmp( szNewDir, "None" ) && strcmp( szNewDir, "Off" ) )
	{
		int i;
		for( i=strlen( szNewDir ); i > 0 && szNewDir[i]!='\\'; i--);
		if( i > 0 )
			szNewDir[i] = 0;
		SetCurrentDirectory( szNewDir );
	}

	if( ulScreenMode & SMALL_DIALOG_MODE )
	{
		CFileSmallDlg fileDlg;
		if( fileDlg.DoModal() == IDOK )
		{
			name = fileDlg.GetPathName();	
			SIO_Dismount( drivenum );
			SIO_Mount( drivenum, name.GetBuffer( 0 ) );
			name.ReleaseBuffer();
		}
	}
	else
	{
		char BASED_CODE szFilter[] = "Atari disk images (*.atr,*.xfd, etc)|*.atr;*.xfd;*.atr.gz;*.atz;*.xfd.gz;*.xfz;*.dcm|ATR Images only (*.atr,*.atr.gz,*.atz)|*.atr;*.atr.gz;*.atz|XFD Images only (*.xfd,*.xfd.gz,*.xfz)|*.xfd;*.xfd.gz;*.xfz|DCM Images only (*.dcm)|*.dcm|All Files (*.*)|*.*||";
		CFileDialog	cfDiskImage( TRUE, NULL, NULL, OFN_EXPLORER | OFN_FILEMUSTEXIST, szFilter, this );

		cfDiskImage.m_ofn.lpstrTitle = szPrompt;
		if( cfDiskImage.DoModal() == IDOK )
		{
			name = cfDiskImage.GetPathName();
			SIO_Dismount( drivenum );
			SIO_Mount( drivenum, name.GetBuffer( 0 ) );
			name.ReleaseBuffer();
			WriteAtari800Drives( NULL );
		}
	}
	SetCurrentDirectory( szCurDir );

	Screen_Clear();
}

BOOL CMainFrame::PreTranslateMessage(MSG* pMsg) 
{
	WPARAM wp = pMsg->wParam;

	switch( pMsg->message )
	{
		//This needs to be handled here instead of a OnXXX message because
		//we want to intercept control keys before they are parsed as accelerators
		case	WM_KEYDOWN:
		{
			if( wp == iCurrentVK )
				return TRUE;

			if( m_iToggleKeys[ wp ] )
			{
				if( ToggleKeyDown( wp ) )
					return TRUE;
			}

			if( (ulMiscStates & ATARI_USE_KEYTEMPLATE) && ucKeysCovered[wp] )
			{
				iNewKey = iKBTable[ wp ];
				
				if( iNewKey != AKEY_NONE )
				{
					if( SHIFT_KEY )
						iNewKey |= AKEY_SHFT;
					if( CTRL_KEY )
						iNewKey |= AKEY_CTRL;

					iNewVK = wp;
					return TRUE;
				}
				iNewVK = 0;
				return TRUE;
			}

			if( SHIFT_KEY && CTRL_KEY )
			{
				iNewKey = m_iShftCtrlKeys[ wp ];
				if( iNewKey != AKEY_NONE )
				{
					iNewVK = wp;
					return TRUE;
				}
				iNewVK = 0;
				return TRUE;
			}

			if( CTRL_KEY )
			{
				if( wp >= VK_F1 && wp <= VK_F8 )
				{
					DriveInsert( wp - VK_F1 + 1);
					return TRUE;
				}
				else
				{
					iNewKey = m_iCtrlKeys[ wp ];
					if( iNewKey != AKEY_NONE )
					{
						iNewVK = wp;
						return TRUE;
					}
				}
				iNewVK = 0;
				return TRUE;
			}

			if( SHIFT_KEY )
			{
				iNewKey = m_iShftKeys[ wp ];
				if( iNewKey != AKEY_NONE )
				{
					iNewVK = wp;
					return TRUE;
				}
				iNewVK = 0;
				return TRUE;
			}
			
			if( m_iNormKeys[ wp] != AKEY_NONE )
			{
				iNewKey = m_iNormKeys[ wp ];
				if( iNewKey != AKEY_NONE )
				{
					iNewVK = wp;
					return TRUE;
				}
				iNewVK = 0;
				return TRUE;
			}

			return CFrameWnd::PreTranslateMessage(pMsg);
			break;
		}

		case	WM_SYSKEYDOWN:
		{
			if( wp == '\r' )
			{
				if( ulScreenMode & DDRAW_FULL )
				{
					ulScreenMode &= ~DDRAW_FULL;
					if( !(ulScreenMode & DDRAW_WIND) && !(ulScreenMode & DDRAW_NONE) )
						ulScreenMode |= DDRAW_NONE;
				}
				else
					ulScreenMode |= DDRAW_FULL;

				WriteRegDWORD( NULL, REG_DDRAW_MODE, ulScreenMode );
				Init_Graphics();
				return TRUE;
			}
			break;
		}

		case	WM_KEYUP:
		{
			if( m_iToggleKeys[ wp ] )
			{
				if( ToggleKeyUp( wp ) )
					return TRUE;
			}

			if( wp == (WPARAM)iCurrentVK )
			{
				iCurrentKey = AKEY_NONE;
				iCurrentVK = 0;
				KEYPRESSED = FALSE;
//				if( iNewKey != AKEY_NONE )
//					iNewVK |= AKEY_PENDING;
			}

			if( wp == (WPARAM)iNewVK )
			{
				if( !(iNewKey & SPECIAL_HANDLER_MASK) )
				{
					iNewKey = AKEY_NONE;
					iNewVK = 0;
				}
			}
		}
		
		default:
			break;
	}
	return CFrameWnd::PreTranslateMessage(pMsg);
}


void CMainFrame::OnSystemDisk() 
{
	if( ulScreenMode & SMALL_DIALOG_MODE )
	{
		CDriveSmallDlg	DriveSmallDlg( this );
		DriveSmallDlg.DoModal();
	}
	else
	{
		CDriveDialog	DriveDialog( this );
		DriveDialog.DoModal();
	}
	Screen_Clear();
}

void CMainFrame::OnAtariHarddisk() 
{
	CHardDiskDlg	hardDisk;
	hardDisk.DoModal();
	Screen_Clear();
}

void CMainFrame::OnAtariHardware() 
{
	CHardwareDlg	HardwareDlg( this );

	HardwareDlg.DoModal();
	Invalidate();
	Screen_Clear();
}

void CMainFrame::OnAtariCartridge() 
{
	CCartridgeDlg	CartridgeDlg( this );

	CartridgeDlg.DoModal();
	Invalidate();
	Screen_Clear();
}

void CMainFrame::OnClose() 
{
	RECT	rc;

	if( sndoutput )
	{
		unsigned int	unPos = 0;

		//Sound file is finished, so modify header and close it.
		unPos = ftell( sndoutput ) - 8;
		fseek( sndoutput, 4, SEEK_SET );	//Seek past RIFF
		fwrite( &unPos, 4, 1, sndoutput );	//Write out size of entire data chunk
		fseek( sndoutput, 40, SEEK_SET );
		unPos -= 36;						
		fwrite( &unPos, 4, 1, sndoutput );	//Write out size of just sample data
		fclose( sndoutput );
	}
	sndoutput = NULL;

	GetWindowRect( &rc );

	if( (rc.left!=0) && (nStartX != rc.left) )
		WriteRegDWORD( NULL, REG_START_XPOS, (DWORD)rc.left );

	if( (rc.top!=0) && (nStartY != rc.top ) )
		WriteRegDWORD( NULL, REG_START_YPOS, (DWORD)rc.top );
	
	CFrameWnd::OnClose();
}

void CMainFrame::OnInfoBenchmark() 
{
	Screen_Benchmark();
	Screen_Clear();
}

void CMainFrame::OnOptionsGraphics() 
{
	int	iReturn;

	if( ulScreenMode & SMALL_DIALOG_MODE )
	{
		CGraphicsSmallDlg	GraphicsSmallDlg( this );
		iReturn = GraphicsSmallDlg.DoModal();
	}
	else
	{
		CGraphicsDlg	GraphicsDlg( this );
		iReturn = GraphicsDlg.DoModal();
	}
	//Show the window because if we changed DDraw modes the frame will be missing 
	//until forced to redraw here
	if( iReturn == IDOK )
		ShowWindow( SW_SHOWNORMAL );
	Screen_Clear();
}

void CMainFrame::OnOptionsSound() 
{
	SoundDlg	Sound;
	Sound.DoModal();
	Screen_Clear();
}

void CMainFrame::OnInfoSoundPokeySpeed() 
{
	int i, unSampleSize;
	ULONG	starttime, totaltime;
	char	*cTmp = NULL;

	if( default_tv_mode == 1 )
		unSampleSize = nSoundRate / 50;
	else
		unSampleSize = nSoundRate / 60;
	cTmp = (char *)calloc( 1, unSampleSize + 1 );
	if( !cTmp )
		return;
	if( !(ulAtariState & ATARI_RUNNING) || (ulSoundState & SOUND_NOSOUND) )
	{
		LoadString( NULL, IDS_SOUND_TEST_WARNING, gcErrorString, LOADSTRING_STRING_SIZE );
		MessageBox( gcErrorString, MB_OK );
		free( cTmp );
		return;
	}
	LoadString( NULL, IDS_SOUND_TEST_BEGIN, gcErrorString, LOADSTRING_STRING_SIZE );
	MessageBox( gcErrorString, MB_OK );
	starttime = timeGetTime();
	for( i=0; i < 60; i++ )
		Pokey_process( (unsigned char *)cTmp, unSampleSize );
	totaltime = timeGetTime() - starttime;
	LoadString( NULL, IDS_SOUND_TEST_RESULT, gcErrorString, LOADSTRING_STRING_SIZE );
	sprintf( cTmp, gcErrorString, unSampleSize, totaltime, (double)totaltime/60.0 );
	MessageBox( cTmp, MB_OK );
	free( cTmp );
	Screen_Clear();
}


void CMainFrame::OnOptionsJoystick() 
{
	CJoyStickDlg	joyDlg;
	CWarnDlg	Warning;
	int	result = IDOK;

	joyDlg.DoModal();
	Screen_Clear();
}

void CMainFrame::OnOptionsLog() 
{
	CErrorLogDlg	ErrorLog;
	ErrorLog.DoModal();
	Screen_Clear();
}

void CMainFrame::OnOptionsSoundfile() 
{
	CWarnDlg	Warning;
	int			result = IDOK;

	if( sndoutput )
	{
		unsigned int	unPos = 0;

		//Sound file is finished, so modify header and close it.
		unPos = ftell( sndoutput ) - 8;
		fseek( sndoutput, 4, SEEK_SET );	//Seek past RIFF
		fwrite( &unPos, 4, 1, sndoutput );	//Write out size of entire data chunk
		fseek( sndoutput, 40, SEEK_SET );
		unPos -= 36;						
		fwrite( &unPos, 4, 1, sndoutput );	//Write out size of just sample data
		fclose( sndoutput );
		sndoutput = NULL;
		LoadString( NULL, IDS_SOUND_FILE_CLOSED, gcErrorString, LOADSTRING_STRING_SIZE );
		MessageBox( gcErrorString, MB_OK );
		return;
	}

	if( ulSoundState & SOUND_NOSOUND )
	{
		LoadString( NULL, IDS_SOUND_RECORD, gcErrorString, LOADSTRING_STRING_SIZE );
		MessageBox( gcErrorString, MB_OK );
	}

	if( !(ulDontShowFlags & DONT_SHOW_SOUNDFILE_WARN ) )
	{
		char	message[LOADSTRING_STRING_SIZE];
		LoadString( NULL, IDS_WARNING_SOUNDFILE, message, LOADSTRING_STRING_SIZE );
		Warning.csWarnText = message;
		Warning.iWarnBit = DONT_SHOW_SOUNDFILE_WARN;
		result = Warning.DoModal();
	}

	if( result==IDOK )
	{
		CString		name;

		name.GetBuffer(MAX_PATH);
		name.Format("%s", "atarisnd" );

		CFileDialog	cfdTransScript( FALSE, "wav", name, OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST, NULL, this );
		cfdTransScript.m_ofn.lpstrTitle = "Name of WAV file to save";
		if( cfdTransScript.DoModal()==IDOK )
		{
			name = cfdTransScript.GetPathName();
			sndoutput = fopen( name.GetBuffer(0), "wb" );
			/*
			The RIFF header: 

			  Offset  Length   Contents
			  0       4 bytes  'RIFF'
			  4       4 bytes  <file length - 8>
			  8       4 bytes  'WAVE'
			
			The fmt chunk: 

			  12      4 bytes  'fmt '
			  16      4 bytes  0x00000010     // Length of the fmt data (16 bytes)
			  20      2 bytes  0x0001         // Format tag: 1 = PCM
			  22      2 bytes  <channels>     // Channels: 1 = mono, 2 = stereo
			  24      4 bytes  <sample rate>  // Samples per second: e.g., 44100
			  28      4 bytes  <bytes/second> // sample rate * block align
			  32      2 bytes  <block align>  // channels * bits/sample / 8
			  34      2 bytes  <bits/sample>  // 8 or 16

			The data chunk: 

			  36      4 bytes  'data'
			  40      4 bytes  <length of the data block>
			  44        bytes  <sample data>
			*/
			fwrite( "RIFF\000\000\000\000WAVEfmt\040\020\000\000\000\001\000\001\000", 24, 1, sndoutput );
			fwrite( &nSoundRate, 4, 1, sndoutput );
			fwrite( &nSoundRate, 4, 1, sndoutput );
			fwrite( "\001\000\010\000data\000\000\000\000", 8, 1, sndoutput );
		}
	}
	Screen_Clear();
}

void CMainFrame::OnMiscClearall() 
{
	int result;

	LoadString( NULL, IDS_CLEAR_AFFIRM, gcErrorString, LOADSTRING_STRING_SIZE );
	result = MessageBox( gcErrorString, "Atari800Win", MB_YESNO );

	if( result == IDYES )
	{
		DeleteAllRegKeys( NULL, REGNAME );
		HandleRegistry();
	}
}

void CMainFrame::OnTimer(UINT nIDEvent) 
{
	if( nIDEvent == TIMER_READ_JOYSTICK )
	{
		ReadJoystickInput( 0, 0 );
		ReadJoystickInput( 1, 0 );
		ReadJoystickInput( 2, 0 );
		ReadJoystickInput( 3, 0 );
		if( !(ulAtariState & ATARI_PAUSED) )
			::KillTimer( MainhWnd, TIMER_READ_JOYSTICK );
	}

	CFrameWnd::OnTimer(nIDEvent);
}

void CMainFrame::OnMove(int x, int y) 
{
	CFrameWnd::OnMove(x, y);

	if( hWnd )
		ComputeClipArea( );
}


void CMainFrame::OnFileDcmtoatr() 
{
	char BASED_CODE szFilter[] = "DCM disk images (*.dcm)|*.dcm|All Files (*.*)|*.*||";
	char cLocalFileBuffer[ 8192 ];
	CFileDialog	cfDiskImage( TRUE, NULL, NULL, OFN_PATHMUSTEXIST | OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT, szFilter, this );

	cLocalFileBuffer[0] = 0;
	cfDiskImage.m_ofn.lpstrFile = &cLocalFileBuffer[0];
	cfDiskImage.m_ofn.nMaxFile = 8192;
	cfDiskImage.m_ofn.lpstrTitle = "Select DCM file(s) to convert";
	if( cfDiskImage.DoModal() == IDOK  )
	{
		FILE *fpInput, *fpOutput;
		CString	strInput;
		char szDestDir[ MAX_PATH ];
		int i;

		strcpy( szDestDir, cfDiskImage.GetPathName( ) );
		for( i = strlen( szDestDir ); i > 0 && szDestDir[i]!= '\\' && szDestDir[i] !='.'; i-- );
		if( i == 0 || szDestDir[i] != '.' )
			i = strlen( szDestDir );
		strcpy( &szDestDir[i], ".atr" );

		CFileDialog	cfDestDir( FALSE, NULL, szDestDir, OFN_PATHMUSTEXIST | OFN_EXPLORER, NULL, this );
		cfDestDir.m_ofn.lpstrTitle = "Select destination directory to write file(s)";
		if( cfDestDir.DoModal() != IDOK )
			return;
		strcpy( szDestDir, cfDestDir.GetPathName() );

		for( i = strlen( szDestDir ); i > 0 && szDestDir[i]!= '\\'; i-- );
		szDestDir[i] = 0;

		if( szDestDir[0] != 0 )
		{
			POSITION	pos = cfDiskImage.GetStartPosition();

			ASSERT( pos );
			if( !pos )
				return;

			strInput = cfDiskImage.GetNextPathName( pos );
			while( strInput != "" )
			{
				char	szFullDestName[ MAX_PATH ];
				char	szThisFileName[ MAX_PATH ];

				strcpy( szThisFileName, strInput.GetBuffer(0) );
				strInput.ReleaseBuffer();
				fpInput = fopen( szThisFileName, "rb" );
				if( !fpInput )
				{
					char szError[ MAX_PATH + 32 ];
					sprintf( szError, "Can't open input file %s", szThisFileName );
					MessageBox( szError, "Atari800Win", MB_OK );
					return;
				}
				for( i = strlen( szThisFileName ); i > 0 && szThisFileName[i]!= '\\'; i-- );
				if( szThisFileName[i] == '\\' )
					i++;

				strcpy( szFullDestName, szDestDir );
				strcat( szFullDestName, "\\" );
				strcat( szFullDestName, &szThisFileName[i] );

				for( i = strlen( szFullDestName ); i > 0 && szFullDestName[i]!= '\\' && szFullDestName[i] !='.'; i-- );
				if( i == 0 || szFullDestName[i] != '.' )
					i = strlen( szFullDestName );
				strcpy( &szFullDestName[i], ".atr" );
				
				fpOutput = fopen( szFullDestName, "rb" );
				if( fpOutput )
				{
					char szWarn[ 256 + MAX_PATH ];
					int result;

					sprintf( szWarn, "The file %s already exists, are you sure you want to overwrite it?", szFullDestName );
					result = MessageBox( szWarn, "Atari800Win", MB_YESNO );
					if( result == IDNO )
					{
						fclose( fpInput );
						return;
					}
					fclose( fpOutput );
				}
				fpOutput = fopen( szFullDestName, "wb" );
				if( !fpOutput )
				{
					char szWarn[ 256 + MAX_PATH ];
					sprintf( szWarn, "The file %s could not be opened for output, stopping operation", szFullDestName );
					MessageBox( szWarn, "Atari800Win", MB_OK );
					return;
				}
				if( !dcmtoatr( fpInput, fpOutput, szThisFileName, szFullDestName ) )
				{
					int result;
					result = MessageBox( "There was an error during the operation and it was aborted. Would you like to check the error log for details?.", "Atari800Win", MB_YESNO );
					fclose( fpInput );
					fclose( fpOutput );
					if( result == IDYES )
					{
						CErrorLogDlg	ErrorLog;
						ErrorLog.DoModal();
					}
					return;
				}
				fclose( fpOutput );
				fclose( fpInput );
				if( pos )
					strInput = cfDiskImage.GetNextPathName( pos );
				else
					strInput = "";
			}
		}
	}
	MessageBox( "Conversion successfull" );

	Screen_Clear();
}

void CMainFrame::OnAtariReboot() 
{
	Atari_ReInit( );
	Invalidate( );
}

void CMainFrame::OnFileReadstate() 
{
	CString	name = "";

	if( zlib_capable() == -1 )
	{
		MessageBox( "Cannot save/restore state files without a working ZLIB.DLL", "Atari800Win", MB_OK );
		return;
	}

	if( !(ulScreenMode & DDRAW_WIND) && !(ulScreenMode & DDRAW_NONE) && ((ulScreenMode & DDRAW_320_200) || (ulScreenMode & DDRAW_320_240)) )
	{
		CFileSmallDlg fileDlg;
		if( fileDlg.DoModal() == IDOK )
			name = fileDlg.GetPathName();	
	}
	else
	{
		char BASED_CODE szFilter[] = "Atari state images (*.a8s)|*.a8s;|All Files (*.*)|*.*||";
		CFileDialog	cfStateFile( TRUE, "a8s", "atarisav.a8s", OFN_EXPLORER | OFN_FILEMUSTEXIST, szFilter, this );

		cfStateFile.m_ofn.lpstrTitle = "Select Atari saved-state file";
		if( cfStateFile.DoModal() == IDOK )
			name = cfStateFile.GetPathName();
	}
	if( name != "" )
	{
		int result = ReadAtariState( name.GetBuffer( 0 ), "rb" );
		name.ReleaseBuffer();
		if( result == FALSE )
		{
			MessageBox( "The Atari read state operation failed. You can check the Atari/Log option to see a description of the problem.", "Atari800Win", MB_OK );
		}

		if( !(ulAtariState & ATARI_PAUSED ))
		{
			Screen_Clear();
			Toggle_Pause();
		}
		DescribeAtariSystem( );
		return;
	}
	ulAtariState &= ~ATARI_PAUSED;
	Screen_Clear();
}

void CMainFrame::SaveState( UINT saverom )
{
	CString	name = "";

	if( zlib_capable() == -1 )
	{
		MessageBox( "Cannot save/restore state files without a working ZLIB.DLL", "Atari800Win", MB_OK );
		return;
	}

	if( saverom )
	{
		int result = MessageBox( "It is not normally necessary to do this. It will save the Atari ROMS and BASIC in your state file, making it larger. The only reason this would be necessary is if you are running with patched ROMS/BASIC. Do you want to continue anyway?", "Atari800Win", MB_YESNO );
		if( result == IDNO )
			return;
	}
	if( !(ulScreenMode & DDRAW_WIND) && !(ulScreenMode & DDRAW_NONE) && ((ulScreenMode & DDRAW_320_200) || (ulScreenMode & DDRAW_320_240)) )
	{
		CFileSmallDlg fileDlg;
		if( fileDlg.DoModal() == IDOK )
			name = fileDlg.GetPathName();	
	}
	else
	{
		char BASED_CODE szFilter[] = "Atari state images (*.a8s)|*.a8s;|All Files (*.*)|*.*||";
		CFileDialog	cfStateFile( FALSE, "a8s", "atarisav.a8s", OFN_EXPLORER | OFN_OVERWRITEPROMPT, szFilter, this );

		cfStateFile.m_ofn.lpstrTitle = "Select Atari saved-state file";
		if( cfStateFile.DoModal() == IDOK )
			name = cfStateFile.GetPathName();
	}
	if( name != "" )
	{
		int result = SaveAtariState( name.GetBuffer( 0 ), "wb", saverom );
		name.ReleaseBuffer();
		if( result == FALSE )
		{
			MessageBox( "The Atari save state operation failed. You can check the Atari/Log option to see a description of the problem.", "Atari800Win", MB_OK );
		}
	}
	DescribeAtariSystem( );
}

void CMainFrame::OnFileSavestate( ) 
{
	SaveState( 0 );
}

void CMainFrame::OnFileSavestateroms() 
{
	SaveState( 1 );
}

void CMainFrame::OnOptionsKeyboard() 
{
	CKeyBoard	KBDialog;
	KBDialog.DoModal();
	Screen_Clear();
}

void CMainFrame::OnAtarLoadexe() 
{
	CString	name = "";
	char	szCurDir[ MAX_PATH ];

	GetCurrentDirectory( MAX_PATH, &szCurDir[0] );
	SetCurrentDirectory( atari_exe_dir );
	if( ulScreenMode & SMALL_DIALOG_MODE )
	{
		CFileSmallDlg fileDlg;
		if( fileDlg.DoModal() == IDOK )
			name = fileDlg.GetPathName();	
	}
	else
	{
		char BASED_CODE szFilter[] = "All Files (*.*)|*.*|Atari executable files (*.com,*.exe)|*.com;*.exe;||";
		CFileDialog	cfStateFile( TRUE, "com", NULL, OFN_EXPLORER | OFN_FILEMUSTEXIST, szFilter, this );

		cfStateFile.m_ofn.lpstrTitle = "Select Atari executable file";
		if( cfStateFile.DoModal() == IDOK )
		{
			CString newpath;
			
			name = cfStateFile.GetPathName();
			newpath = name.Left( name.ReverseFind( '\\' ) );
			if( newpath != atari_exe_dir )
			{
				strcpy( atari_exe_dir, newpath );
				WriteRegString( NULL, REG_EXEPATH, atari_exe_dir );
			}
		}
	}
	if( name != "" )
	{
		int result = ReadAtariExe( name.GetBuffer( 0 ) );
		name.ReleaseBuffer();
		if( result == FALSE )
		{
			MessageBox( "Could not read Atari executable. You can check the Atari/Log option to see a description of the problem.", "Atari800Win", MB_OK );
		}
	}
	SetCurrentDirectory( szCurDir );
	DescribeAtariSystem( );
	Screen_Clear();
	return;
}

void CMainFrame::OnOptionsArtif() 
{
	global_artif_mode++;
	if( global_artif_mode > 4 )
		global_artif_mode = 0;
	art_main_init( 0, global_artif_mode );
	WriteRegDWORD( NULL, REG_ARTIF_MODE, global_artif_mode );
}
