/*
	WinSTon
*/

#include "..\includes\winston.h"
#include "..\includes\configuration.h"
#include "..\includes\decode.h"
#include "..\includes\debugger.h"
#include "..\includes\dialog.h"
#include "..\includes\creatediscimage.h"
#include "..\includes\daudio.h"
#include "..\includes\debug.h"
#include "..\includes\joy.h"
#include "..\includes\djoy.h"
#include "..\includes\dsurface.h"
#include "..\includes\errlog.h"
#include "..\includes\file.h"
#include "..\includes\floppy.h"
#include "..\includes\gemdos.h"
#include "..\includes\ikbd.h"
#include "..\includes\intercept.h"
#include "..\includes\reset.h"
#include "..\includes\m68000.h"
#include "..\includes\memorysnapshot.h"
#include "..\includes\misc.h"
#include "..\includes\printer.h"
#include "..\includes\rs232.h"
#include "..\includes\screen.h"
#include "..\includes\shortcut.h"
#include "..\includes\sound.h"
#include "..\includes\tables.h"
#include "..\includes\timer.h"
#include "..\includes\toolbar.h"
#include "..\includes\tos.h"
#include "..\includes\video.h"
#include "..\includes\view.h"
#include "..\includes\ymformat.h"

//#define TRAP_EXCEP_HISTORY		// Trap errors,GPFs and output history etc... to debug file before quit
DLG_PARAMS ConfigureParams,DialogParams;

HINSTANCE hInst;										// Application instance
HWND hWnd;												// Our window handle
HDC MainDC;												// Global device context for drawing
HACCEL hAccel;											// Accelerators for CTRL-x etc...
//MSG Msg;												// Msg structure for windows message handler
HANDLE hVBLHandle=NULL;									// Timer handle for emulation speed
MMRESULT hSoundTimer;									// Handle to sound playback thread
MMRESULT hSpeedTimer=NULL;								// Handle to speed governing thread
BOOL bQuitProgram=FALSE;								// Flag to quit program cleanly
BOOL bEmulationActive=EMULATION_ACTIVE;					// Run emulation when start WinSTon(we'll be in Windows mouse mode!)
BOOL bAppActive = FALSE;
unsigned int TimerID;									// Timer ID for main window
char szName[] = { "WinSTon" };
char szBootDiscImage[MAX_FILENAME_LENGTH] = { "" };

char szWorkingDir[MAX_FILENAME_LENGTH] = { "" };
char szCurrentDir[MAX_FILENAME_LENGTH] = { "" };

unsigned char STRam[16*1024*1024];						// This is our ST Ram, includes all TOS/hardware areas for ease
extern BOOL bUseVDIRes ;

int STSpeedMilliSeconds[] = {							// Convert option 'nMinMaxSpeed' into milliseconds
	1000/50,								// MINMAXSPEED_MIN(20ms)
	1000/66,								// MINMAXSPEED_1(15ms)
	1000/100,								// MINMAXSPEED_2(10ms)
	1000/200,								// MINMAXSPEED_3(5ms)
	1,										// MINMAXSPEED_MAX(1ms)
};

//-----------------------------------------------------------------------
/*
	Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
*/
void WinSTon_MemorySnapShot_Capture(BOOL bSave)
{
	int nBytes;

	// Save/Restore details
	// Only save/restore area of memory machine ie set to, eg 1Mb
	if (bSave) {
		nBytes = STRamEnd_BusErr;
		MemorySnapShot_Store(&nBytes,sizeof(nBytes));
		MemorySnapShot_Store(STRam,nBytes);
	}
	else {
		MemorySnapShot_Store(&nBytes,sizeof(nBytes));
		MemorySnapShot_Store(STRam,nBytes);
	}
	// And Cart/TOS/Hardware area
	MemorySnapShot_Store(&STRam[0xE00000],0x200000);
	MemorySnapShot_Store(szBootDiscImage,sizeof(szBootDiscImage));
	MemorySnapShot_Store(szWorkingDir,sizeof(szWorkingDir));
	MemorySnapShot_Store(szCurrentDir,sizeof(szCurrentDir));
}

//-----------------------------------------------------------------------
/*
	Open Windows Explorer on local machine or Internet
*/
void WinSTon_GoWeb(char *pszWebPage, BOOL bAccessWeb)
{
	/*
	char szWebPageName[MAX_FILENAME_LENGTH];

	// Always go back to a Window!
	Screen_ReturnFromFullScreen();
	// Restore a few things
	View_ToggleWindowsMouse(MOUSE_WINDOWS);				// Put mouse into Windows mode
	View_LimitCursorToScreen();							// Free mouse from Window constraints

	// Find help HTML page(include speech marks) - Windows may have change directory so look from default is on local machine
	if (bAccessWeb) {
		// Are we trying to access the LGD? Is so, add something like '&winston=v0.3' on the end
		if (!strnicmp(pszWebPage,LGD_DOWNLOAD_STRING,strlen(LGD_DOWNLOAD_STRING)))
			sprintf(szWebPageName,"%s&winston=%s",pszWebPage,PROG_VERSION);
		else
			sprintf(szWebPageName,"%s",pszWebPage);
	}
	else
		sprintf(szWebPageName,"%s\\%s",szWorkingDir,pszWebPage);

	// Run 'explorer'
	ShellExecute(hWnd,"open",szWebPageName,NULL,NULL,SW_SHOWNORMAL);
	*/
}

//-----------------------------------------------------------------------
/*
	Error handler
*/


void WinSTon_SysError(char *Error,char *Title)
{
	//doxxx
	//MessageBox(hWnd,Error,Title,MB_OK | MB_ICONSTOP);
	writexbox( Title ) ;
	writexbox( "\r\n" ) ;
	writexbox( Error ) ;
}

//-----------------------------------------------------------------------
/*
	Bring up message(handles full-screen as well as Window)
*/
int WinSTon_Message(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT uType)
{
	//doxxx
	writexbox( (char*)lpCaption ) ;
	writexbox( "\r\n" ) ;
	writexbox( (char*)lpText ) ;

	/*
	int Ret;

	// Are we in full-screen?
	if (bInFullScreen)
		Screen_ReturnFromFullScreen();

	// Show message
	Ret = MessageBox(hWnd,lpText,lpCaption,uType);

	return(Ret);
	*/

	return 0 ;
}

//-----------------------------------------------------------------------
/*
	Pause emulation, stop sound
*/
void WinSTon_PauseEmulation(void)
{
	bEmulationActive = EMULATION_INACTIVE;
}

//-----------------------------------------------------------------------
/*
	Start emulation
*/
void WinSTon_UnPauseEmulation(void)
{
//	SetMenu(hWnd,NULL);									// Remove any menu's!
	bFullScreenHold = FALSE;							// Release hold	
	Screen_SetFullUpdate();								// Cause full screen update(to clear all)

	bEmulationActive = EMULATION_ACTIVE;
	//DAudio_ResetBuffer();
}

//-----------------------------------------------------------------------
/*
	Window message handler
*/
long FAR PASCAL WinSTon_WndProc(HWND hWnd, UINT Message, UINT wParam, LONG lParam)
{
	/*
	HDC hDC;
//	PAINTSTRUCT ps;
	MINMAXINFO *MinMaxInfo;
	RECT Rect;

	switch(Message) {
		case WM_TIMER:
//			char szString[256];
//			sprintf(szString,"%d %d  %d",KeyboardProcessor.Mouse.DeltaX,KeyboardProcessor.Mouse.DeltaY,KeyboardProcessor.MouseMode);
//			SetWindowText(hWnd,szString);
			nVBLs = 0;
			return(0);

		case WM_DROPFILES:
			// Drop file onto WinSTon - insert into drive and re-boot emulator
			View_DropFile((HDROP)wParam);
			return(0);

		case WM_SYSCOMMAND:
			// This code prevents any power management features cutting in
			switch (wParam&0xfff0) {
				case SC_MONITORPOWER:
				case SC_SCREENSAVE:
						return(0);						// Don't time out
			}
			break;

		case WM_SYSKEYDOWN:
			if (View_SysKeyDown(hWnd,wParam,lParam))
				return(0);
			break;
		case WM_SYSKEYUP:
			if (View_SysKeyUp(hWnd,wParam,lParam))
				return(0);
			break;

		case WM_KEYDOWN:
			View_KeyDown(hWnd,wParam,lParam);
			return(0);
		case WM_KEYUP:
			View_KeyUp(hWnd,wParam,lParam);
			return(0);

		case WM_LBUTTONDBLCLK:							// ( This also the 3rd part of the DOWN/UP/DOWN/UP sequence(DOWN/UP/DCLK/UP) )
			if (bWindowsMouseMode || (ConfigureParams.Configure.nMinMaxSpeed==MINMAXSPEED_MIN)
			  || ConfigureParams.Screen.Advanced.bSyncToRetrace )
				View_LeftMouseButtonDown(hWnd,wParam,lParam);
			else
				Keyboard.LButtonDblClk = 1;				// Start double-click sequence in emulation time
			return(0);
		case WM_RBUTTONDBLCLK:
			if (bWindowsMouseMode || (ConfigureParams.Configure.nMinMaxSpeed==MINMAXSPEED_MIN))
				View_RightMouseButtonDown(hWnd,wParam,lParam);
			else
				Keyboard.RButtonDblClk = 1;
			return(0);

		case WM_MOUSEMOVE:
			View_MouseMove(hWnd,wParam,lParam);
			return(0);
		case WM_LBUTTONDOWN:
			View_LeftMouseButtonDown(hWnd,wParam,lParam);
			return(0);
		case WM_LBUTTONUP:
			View_LeftMouseButtonUp(hWnd,wParam,lParam);
			return(0);
		case WM_RBUTTONDOWN:
			View_RightMouseButtonDown(hWnd,wParam,lParam);
			return(0);
		case WM_RBUTTONUP:
			View_RightMouseButtonUp(hWnd,wParam,lParam);
			return(0);

		case WM_MOVE:
			// We've moved the window, store (if not Max/Min) so can re-start at same pos on next run
			if ( !IsZoomed(hWnd) && !IsIconic(hWnd) ) {
				GetWindowRect(hWnd,&Rect);
				WindowInitRect.left = Rect.left;
				WindowInitRect.top = Rect.top;
			}
			return(0);

		case WM_SIZE:
			// Limit cursor to new window extents
			View_LimitCursorToClient();
			return(0);

		case WM_GETMINMAXINFO:
			MinMaxInfo = (MINMAXINFO *)lParam;

			// Find Window minimum border size for this ST resolution and options settings
			View_GetMinBorderRect(&Rect);
			View_AdjustWindowSizeFromClient(&Rect);

			MinMaxInfo->ptMinTrackSize.x = Rect.right+BORDER_WIDTH;
			MinMaxInfo->ptMinTrackSize.y = Rect.bottom+BORDER_HEIGHT;
			return(0);

		case WM_ACTIVATEAPP:
			// Are we loosing focus? Stop emulation
			if ((BOOL)wParam==FALSE) {
				Screen_ReturnFromFullScreen();
				View_LimitCursorToScreen();
				WinSTon_PauseEmulation();
				DAudio_StopBuffer();
				bAppActive = FALSE;
			}
			else {		// NOTE will send this message if resize windows etc... Use bAppActive flag to see if really activated
				if (!bAppActive) {
					// We we in ST mouse mode? If so, restart emulation
					if (!bWindowsMouseMode) {
						WinSTon_UnPauseEmulation();
					}
				}
				bAppActive = TRUE;
			}
			return(0);

		case WM_COMMAND:
			// Pop-up menus
			switch(wParam) {
				// Reset
				case ID_RESET_COLDRESET:
					ToolBar_Activate_Reset(FALSE,RESETQUERY_RESET,TRUE);
					return(TRUE);
				case ID_RESET_WARMRESET:
					ToolBar_Activate_Reset(FALSE,RESETQUERY_RESET,FALSE);
					return(TRUE);
				case ID_RESET_EXIT:
					PostMessage(hWnd,WM_CLOSE,NULL,NULL);
					return(TRUE);

				// Floppy A
				case ID_FLOPPYA_INSERTDISC:
					ToolBar_OpenFloppyDialog(0,FALSE,RESETQUERY_RESET);
					return(TRUE);
				case ID_FLOPPYA_INSERTDISC_NORESET:
					ToolBar_OpenFloppyDialog(0,FALSE,RESETQUERY_NORESET);
					return(TRUE);
				case ID_FLOPPYA_EJECT:
					Floppy_EjectDiscFromDrive(0,TRUE);
					return(TRUE);
				case ID_FLOPPYA_CREATE:
					Dialog_DiscImage_CreateBlankImage(hWnd,0);
					return(TRUE);
				case ID_FLOPPYA_INSERT_SLOT1:
				case ID_FLOPPYA_INSERT_SLOT2:
				case ID_FLOPPYA_INSERT_SLOT3:
				case ID_FLOPPYA_INSERT_SLOT4:
					Floppy_InsertDiscIntoDrive(0,szPreviousImageFilenames[0][wParam-ID_FLOPPYA_INSERT_SLOT1]);
					return(TRUE);

				// Floppy B
				case ID_FLOPPYB_INSERTDISC_NORESET:
					ToolBar_OpenFloppyDialog(1,FALSE,RESETQUERY_NORESET);
					return(TRUE);
				case ID_FLOPPYB_EJECT:
					Floppy_EjectDiscFromDrive(1,TRUE);
					return(TRUE);
				case ID_FLOPPYB_CREATE:
					Dialog_DiscImage_CreateBlankImage(hWnd,1);
					return(TRUE);
				case ID_FLOPPYB_INSERT_SLOT1:
				case ID_FLOPPYB_INSERT_SLOT2:
				case ID_FLOPPYB_INSERT_SLOT3:
				case ID_FLOPPYB_INSERT_SLOT4:
					Floppy_InsertDiscIntoDrive(1,szPreviousImageFilenames[1][wParam-ID_FLOPPYB_INSERT_SLOT1]);
					return(TRUE);

				// Options
				case ID_OPTIONS_SETTINGS:
					ToolBar_Activate_Options();
					return(TRUE);
				case ID_OPTIONS_FAVOURITES:
					ToolBar_Activate_Favourites();
					return(TRUE);
				case ID_OPTIONS_SOUND:
					ShortCut_SoundOnOff();
					View_SetMenuChecks();
					return(TRUE);
				case ID_OPTIONS_MAXSPEED:
					ShortCut_MaximumSpeed();
					View_SetMenuChecks();
					return(TRUE);
				case ID_OPTIONS_CURSOREMU:
					ShortCut_JoystickCursorEmulation();
					View_SetMenuChecks();
					return(TRUE);

				// Help
				case ID_HELP_WINSTON:
					ToolBar_Activate_Help();
					return(TRUE);
			}
			break;

		case WM_SYSCOLORCHANGE:
			// Update buttons in view, as need remapping
			View_LoadBitmaps();
			return(0);

		case WM_PAINT:
			hDC = BeginPaint(hWnd,&ps);
			
			// And refresh screen
			View_Update();

			EndPaint(hWnd,&ps);
			return(0);

		case WM_CLOSE:
			// End any YM recording here, don't inform user
			if (Sound_AreWeRecording())
				Sound_EndRecording(NULL);

			bQuitProgram = TRUE;
			return(FALSE);

		case WM_DESTROY:
			return(0);
	}
	
	return DefWindowProc(hWnd,Message,wParam,lParam);
	*/
return 0 ;

}

//-----------------------------------------------------------------------
/*
	Execute single window message, return TRUE if get quit message
*/
BOOL WinSTon_ExecuteWindowsMessage(void)
{
	/*
	if (bQuitProgram)									// Have already signalled quit?
		return(TRUE);

	if ( PeekMessage(&Msg,NULL,0,0,PM_NOREMOVE) ) {
		if ( !GetMessage(&Msg,NULL,0,0) ) {
			return(TRUE);								// Quit now
		}
#ifdef USE_DEBUGGER
		else if (!TranslateAccelerator(DebughWnd,hAccel,&Msg)) {
#else
		else {
#endif
			TranslateMessage(&Msg);
			DispatchMessage(&Msg);
		}
	}

	return(FALSE);
	*/
	return FALSE ;

}

//-----------------------------------------------------------------------
/*
	Exectute any windows messages, call every 25 frames per second or so(from emulator VBL handler)
*/
BOOL WinSTon_RunWindowsMessageHandler(void)
{
	//doxxx
	/*
	BOOL bRet=FALSE;

	// Any message to execute?
#ifndef USE_DEBUGGER
try_again:
#endif
	while( PeekMessage(&Msg,NULL,0,0,PM_NOREMOVE) && !bRet ) {
		bRet = WinSTon_ExecuteWindowsMessage();			// Return TRUE if want to quit application
	}

#ifndef USE_DEBUGGER
	// Are we stuck in windows loop?
	if ( (bRet==FALSE) && (bEmulationActive==EMULATION_INACTIVE) ) {
		// Suspend thread until a message occurs to free up CPU
		WaitMessage();
		goto try_again;
	}
#endif

	return(bRet);
	*/

	return FALSE ;
}

//-----------------------------------------------------------------------
/*
	Create an event which is times our VBL(50fps) to govern the speed of the emulator
	This changes to vary emulation speed according to user settings
*/
void WinSTon_CreateVBLEvent(void)
{
	hVBLHandle = CreateEvent(NULL,	// pointer to security attributes
							FALSE,	// flag for manual-reset event
							FALSE,	// flag for initial state
							NULL);	// pointer to event-object name
}

//-----------------------------------------------------------------------
/*
	Delete VBL timer
*/
void WinSTon_DeleteVBLEvent(void)
{
	if (hVBLHandle) {
		CloseHandle(hVBLHandle);
		hVBLHandle = NULL;
	}
}

//-----------------------------------------------------------------------
/*
	Signal VBL timer event - used in 'WinSTon_WaitVBLEvent'
*/
void WinSTon_SetVBLEvent(void)
{
	if (hVBLHandle)
		SetEvent(hVBLHandle);
}

//-----------------------------------------------------------------------
/*
	Wait for VBL counter to latch to next frame(called by sound callback @ 20ms, 50fps)
*/
void WinSTon_WaitVBLEvent(void)
{
	// Wait until event signalled by Sound VBL, this need to be more Windows friendly
	if (hVBLHandle) {
		if (WaitForSingleObject(hVBLHandle,50)==WAIT_TIMEOUT) {		// Suspend thread until VBL count increases
			// Something went wrong, reset, try again
			WinSTon_SetSpeedThreadTimer(ConfigureParams.Configure.nMinMaxSpeed);
		}
	}
}

//-----------------------------------------------------------------------
/*
	Check VBL event to see if already set, and return TRUE
*/
BOOL WinSTon_AlreadyWaitingVBLEvent(void)
{
	// Test event to see if already set
	if (WaitForSingleObject(hVBLHandle,0)==WAIT_TIMEOUT)
		return(FALSE);

	return(TRUE);
}

//-----------------------------------------------------------------------
/*
	Create sound thread to handle passing of sound on to DirectSound
*/
void WinSTon_CreateSoundThread(void)
{
	// Create thread to run every 20ms(50fps) to send emulation samples to DirectSound
	hSoundTimer = timeSetEvent(20,1,WinSTon_SoundThreadFunc,0,TIME_PERIODIC);
}

//-----------------------------------------------------------------------
/*
	This thread runs at 50fps and passes sound samples to direct sound and also also
	set the counter/events to govern emulation speed to match the two together.
	When running at a speed other than standard ST speed the VBL event is set by 'WinSTon_SpeedThreadFunc'
	which occurs at differing speeds.
*/
void CALLBACK WinSTon_SoundThreadFunc( UINT wTimerID, UINT msg, DWORD dwUsers, DWORD dw1, DWORD dw2 )
{
	// Advance frame counter, used to draw screen to window at 50fps
	VBLCounter++;

	// Set event so waiting screen draw routine will continue
	if (ConfigureParams.Configure.nMinMaxSpeed==MINMAXSPEED_MIN) {
		// Do wish to skip frames?
		if (ConfigureParams.Screen.Advanced.bFrameSkip) {
			if (VBLCounter&1)
				WinSTon_SetVBLEvent();					// 25fps, with frame-skip
		}
		else
			WinSTon_SetVBLEvent();						// 50fps
	}

	// And play sound through DirectSound, if enabled
	if ( (ConfigureParams.Sound.bEnableSound) && bAppActive )
		Sound_PassYMSamplesToDirectSound();
}

//-----------------------------------------------------------------------
/*
	When running in non-standard ST speed this sets the VBL event to increase the
	running speed of the emulator
*/
void CALLBACK WinSTon_SpeedThreadFunc( UINT wTimerID, UINT msg, DWORD dwUsers, DWORD dw1, DWORD dw2 )
{
	// Advance screen update counter - ONLY if in max speed mode
	if (ConfigureParams.Configure.nMinMaxSpeed!=MINMAXSPEED_MIN)
		WinSTon_SetVBLEvent();
}

//-----------------------------------------------------------------------
/*
	Set timer for 'WinSTon_SpeedThreadFunc' to govern fast than ST emulation speed
	When running in min/max speed this thread is ignored
*/
void WinSTon_SetSpeedThreadTimer(int nMinMaxSpeed)
{
	// Do we have an old timer? If so kill it
	if (hSpeedTimer) {
		timeKillEvent(hSpeedTimer);
		hSpeedTimer = NULL;
	}

	// Set new timer, according to MINMAXSPEED_xxxx
	//if ( ( (nMinMaxSpeed!=MINMAXSPEED_MIN) && nMinMaxSpeed!=MINMAXSPEED_MAX) && (!bQuitProgram) )
		hSpeedTimer = timeSetEvent(STSpeedMilliSeconds[nMinMaxSpeed],1,WinSTon_SpeedThreadFunc,0,TIME_PERIODIC);
}

//-----------------------------------------------------------------------
/*
	Check for any passed parameters
	Used to disable DirectDraw, DirectSound and DirectInput for machines with problems
*/
void WinSTon_ReadParameters(char *pszCmdStrings)
{
	/*
	char szStrings[MAX_PASSED_PARAMETERS][1024];
	int i;

	// Blank
	for(i=0; i<MAX_PASSED_PARAMETERS; i++)
		szStrings[i][0] = '\0';
	// Cut into parameters
	sscanf(pszCmdStrings,"%s %s %s %s",&szStrings[0],&szStrings[1],&szStrings[2],&szStrings[3]);
	// Scan for any which we can use
	for(i=0; i<MAX_PASSED_PARAMETERS; i++) {
		if (strlen(szStrings[i])>0) {
			if (!stricmp(szStrings[i],"-nodirectdraw")) {
				ErrLog_File("-nodirectdraw flag passed, DirectDraw: DISABLED\n");
				bDisableDirectDraw = TRUE;
			}
			else if (!stricmp(szStrings[i],"-nodirectsound")) {
				ErrLog_File("-nodirectsound flag passed, DirectSound: DISABLED\n");
				bDisableDirectSound = TRUE;
			}
			else if (!stricmp(szStrings[i],"-nodirectinput")) {
				bDisableDirectInput = TRUE;
				ErrLog_File("-nodirectinput flag passed, DirectInput: DISABLED\n");
			}
			else {
				// Possible passed disc image filename, ie starts with character other than '-'
				if (szStrings[i][0]!='-')
					strcpy(szBootDiscImage,szStrings[i]);
			}
		}
	}
	*/
}

//-----------------------------------------------------------------------
/*
	Initialise emulation
*/
void WinSTon_Init(void)
{
	Misc_SeedRandom(1043618);
	//Dialog_Favourites_Init();
	//Favourites_Load();
	//Printer_Init();
	//RS232_Init();
	//Configuration_Init();
	//View_CreateWindow();
//	DSurface_Init();
	//View_ShowWindow();
	Timer_Init();
	File_Init();
	Screen_Init();
	Floppy_Init();
	Reset_Cold();
	GemDOS_Init();
	Tables_Init();
	Intercept_Init();
	Joy_Init();
	//DAudio_Init();
	Sound_Init();
	WinSTon_CreateVBLEvent();
	//WinSTon_CreateSoundThread();

	// Check passed disc image parameter, boot directly into emulator
	if (strlen(szBootDiscImage)>0) {
		Floppy_InsertDiscIntoDrive(0,szBootDiscImage);
		//View_ToggleWindowsMouse(MOUSE_ST);
	}
}

//-----------------------------------------------------------------------
/*
	Un-Initialise emulation
*/
void WinSTon_UnInit(void)
{
	//Favourites_Save();
	//Favourites_DeleteAllFolders();
	//Dialog_Favourites_UnInit();
	Screen_ReturnFromFullScreen();
	//WinSTon_SetSpeedThreadTimer(-1);
	WinSTon_DeleteVBLEvent();
	//timeKillEvent(hSoundTimer);
	Floppy_EjectBothDrives();
	Floppy_UnInit();
	//RS232_UnInit();
	//Printer_UnInit();
	//DJoy_UnInit();
	Intercept_UnInit();
	//DAudio_UnInit();
//	DSurface_UnInit();
	//YMFormat_FreeRecording();
	//View_LimitCursorToScreen();
	//View_CloseWindow();
	Screen_UnInit();

	// Release Windows handles
//	ReleaseDC(hWnd,MainDC);
	//MainDC = NULL;
	// And Quit
	//PostQuitMessage(0);

#ifdef USE_DEBUGGER
	FreeDebugDialog();
#endif
	//Configuration_UnInit();
}

//-----------------------------------------------------------------------
/*
	Main
*/

unsigned int g_wRefreshRate ;

int PASCAL winston_main( char *stfilename, unsigned int refreshrate, unsigned int amtmemory, unsigned int tos)
{
	
	//WNDCLASS WndClass;
	//INITCOMMONCONTROLSEX CommonControls;

	g_wRefreshRate = refreshrate ;

	// Generate random seed
	srand((int)timeGetTime());

	bQuitProgram = FALSE ;

	// Get working directory, if in MSDev force
	Misc_FindWorkingDirectory();
#ifdef FORCE_WORKING_DIR
	//GetCurrentDirectory(MAX_FILENAME_LENGTH,szWorkingDir);
#endif

	// Create debug files
	Debug_OpenFiles();
	ErrLog_OpenFile();

	// Check for any passed parameters, eg -nodirectdraw, -nodirectsound or -nodirectinput
	//WinSTon_ReadParameters(lpszCmdParam);

	bUseVDIRes = FALSE ;
	bUseHighRes = FALSE ;

	strcpy(szBootDiscImage,stfilename);

	//ConfigureParams.Configure.nMinMaxSpeed = ConfigureParams.Configure.nPrevMinMaxSpeed = MINMAXSPEED_MAX;
	ConfigureParams.Configure.nMinMaxSpeed = ConfigureParams.Configure.nPrevMinMaxSpeed = MINMAXSPEED_MIN;

	ConfigureParams.Screen.bFullScreen = TRUE;
	ConfigureParams.Screen.Advanced.bDoubleSizeWindow = FALSE;
	ConfigureParams.Screen.Advanced.bAllowOverscan = TRUE;

	ConfigureParams.Screen.Advanced.bInterlacedFullScreen = FALSE;
	//ConfigureParams.Screen.Advanced.bInterlacedFullScreen = TRUE;

	ConfigureParams.Screen.Advanced.bSyncToRetrace = FALSE;
	ConfigureParams.Screen.Advanced.bFrameSkip = FALSE;	
	//ConfigureParams.Screen.ChosenDisplayMode = DISPLAYMODE_16COL_LOWRES;
	ConfigureParams.Screen.ChosenDisplayMode = DISPLAYMODE_HICOL_HIGHRES;
	ConfigureParams.Screen.bCaptureChange = FALSE;
	ConfigureParams.Screen.nFramesPerSecond = 1;
	ConfigureParams.Screen.bUseHighRes = TRUE;

	ConfigureParams.Joysticks.bUseDirectInput = TRUE;
	for(int i=0; i<2; i++) {
		ConfigureParams.Joysticks.Joy[i].bCursorEmulation = FALSE;
		ConfigureParams.Joysticks.Joy[i].bEnableAutoFire = FALSE;
	}
	
	ConfigureParams.Keyboard.bDisableKeyRepeat = TRUE;
	ConfigureParams.Keyboard.ShortCuts[SHORT_CUT_F11][SHORT_CUT_KEY] = SHORTCUT_FULLSCREEN;
	ConfigureParams.Keyboard.ShortCuts[SHORT_CUT_F11][SHORT_CUT_SHIFT] = SHORTCUT_NOTASSIGNED;
	ConfigureParams.Keyboard.ShortCuts[SHORT_CUT_F11][SHORT_CUT_CTRL] = SHORTCUT_NOTASSIGNED;
	ConfigureParams.Keyboard.ShortCuts[SHORT_CUT_F12][SHORT_CUT_KEY] = SHORTCUT_MOUSEMODE;
	ConfigureParams.Keyboard.ShortCuts[SHORT_CUT_F12][SHORT_CUT_SHIFT] = SHORTCUT_NOTASSIGNED;
	ConfigureParams.Keyboard.ShortCuts[SHORT_CUT_F12][SHORT_CUT_CTRL] = SHORTCUT_NOTASSIGNED;
	strcpy(ConfigureParams.Keyboard.szMappingFileName,"");

	ConfigureParams.Sound.bEnableSound = TRUE;
	ConfigureParams.Sound.nPlaybackQuality = PLAYBACK_HIGH;
	strcpy(ConfigureParams.Sound.szYMCaptureFileName,"");
	
	ConfigureParams.Memory.nMemorySize = amtmemory;
	//ConfigureParams.Memory.nMemorySize = MEMORY_SIZE_1Mb;
	strcpy(ConfigureParams.Memory.szMemoryCaptureFileName,"");

	ConfigureParams.DiscImage.bAutoInsertDiscB = TRUE;
	sprintf(ConfigureParams.DiscImage.szDiscImageDirectory,"%s","D:\\STDISKS");
	File_AddSlashToEndFileName(ConfigureParams.DiscImage.szDiscImageDirectory);

	ConfigureParams.HardDisc.nDriveList = DRIVELIST_CD;
	ConfigureParams.HardDisc.bBootFromHardDisc = FALSE;
	ConfigureParams.HardDisc.nHardDiscDir = DRIVE_D;
	for(i=0; i<MAX_HARDDRIVES; i++) {
		sprintf(ConfigureParams.HardDisc.szHardDiscDirectories[i],"%s\\Hard_Drv","D:\\STDISKS");
		File_CleanFileName(ConfigureParams.HardDisc.szHardDiscDirectories[i]);
	}

	switch ( tos )
	{
		case 1 : sprintf(ConfigureParams.TOSGEM.szTOSImageFileName,"%s","D:\\TOS_A.ROM"); break ;
		case 2 : sprintf(ConfigureParams.TOSGEM.szTOSImageFileName,"%s","D:\\TOS_B.ROM"); break ;
		case 3 : sprintf(ConfigureParams.TOSGEM.szTOSImageFileName,"%s","D:\\TOS_C.ROM"); break ;
		case 0 : 
		default : sprintf(ConfigureParams.TOSGEM.szTOSImageFileName,"%s",""); break ;
	}

	
	//for(i=0; i<MAX_TOSIMAGE_COMBO_IMAGES; i++)
		//strcpy(szComboTOSImages[i],"");
	//strcpy(szComboTOSImages[0],ConfigureParams.TOSGEM.szTOSImageFileName);
	//File_AddSlashToEndFileName(ConfigureParams.TOSGEM.szTOSImageFileName);
	ConfigureParams.TOSGEM.bUseTimeDate = FALSE;
	ConfigureParams.TOSGEM.bAccGEMGraphics = FALSE;
	ConfigureParams.TOSGEM.bUseExtGEMResolutions = FALSE;
	ConfigureParams.TOSGEM.nGEMResolution = GEMRES_640x480;
	ConfigureParams.TOSGEM.nGEMColours = GEMCOLOUR_16;

	ConfigureParams.RS232.bEnableRS232 = FALSE;
	ConfigureParams.RS232.nCOMPort = COM_PORT_1;

	ConfigureParams.Printer.bEnablePrinting = FALSE;
	ConfigureParams.Printer.bPrintToFile = FALSE;
	strcpy(ConfigureParams.Printer.szPrintToFileName,"");

	ConfigureParams.Favourites.bCheckDiscs = TRUE;
	ConfigureParams.Favourites.bOnlyShowIfExist = FALSE;

	/*
	DLG_CONFIGURE Configure;
	DLG_SCREEN Screen;
	DLG_JOYSTICKS Joysticks;
	DLG_KEYBOARD Keyboard;
	DLG_SOUND Sound;
	DLG_MEMORY Memory;
	DLG_DISCIMAGE DiscImage;
	DLG_HARDDISC HardDisc;
	DLG_TOSGEM TOSGEM;
	DLG_RS232 RS232;
	DLG_PRINTER Printer;
	DLG_FAVOURITES Favourites;
	*/
	
	/*
#ifdef TRAP_EXCEP_HISTORY
    LPEXCEPTION_POINTERS ep;
    __try
#endif
	{
		hInst = hInstance;
		if (!hPrevInstance) {
			WndClass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_SAVEBITS;
			WndClass.lpfnWndProc = WinSTon_WndProc;
			WndClass.cbClsExtra = 0;
			WndClass.cbWndExtra = 0;
			WndClass.hInstance = hInst;
			WndClass.hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON1));
			WndClass.hCursor = NULL;
			WndClass.hbrBackground = NULL;
			WndClass.lpszMenuName = NULL;
			WndClass.lpszClassName = szName;

			RegisterClass(&WndClass);
		}
		// Need this for common dialogs - lots of people forget it!
		CommonControls.dwSize = sizeof(INITCOMMONCONTROLSEX);
		CommonControls.dwICC = ICC_WIN95_CLASSES;
		InitCommonControlsEx(&CommonControls);
#ifdef USE_DEBUGGER
		hAccel = LoadAccelerators(hInstance,MAKEINTRESOURCE(IDR_ACCELERATOR1));
#endif
*/
		// Find which Windows version we are running, save to log file
		//Misc_FindWindowsVersion();
		// Init emulator system
		WinSTon_Init();


		// Bring up our Window
		//ShowWindow(hWnd,nCmdShow);
		//UpdateWindow(hWnd);
		// Set timing threads to govern timing and debug display


		//WinSTon_SetSpeedThreadTimer(ConfigureParams.Configure.nMinMaxSpeed);


		//TimerID = SetTimer(hWnd,1,1000,NULL);

#ifdef USE_DEBUGGER
		// Run our debugger
		Debugger_ffInit();
		WinSTon_UnPauseEmulation();
		// Run messages until quit
		for(;;) {
			if (WinSTon_ExecuteWindowsMessage())
				break;
		}
#else
		bAppActive = TRUE ;

		// Run release emulation
		WinSTon_RunWindowsMessageHandler();
		WinSTon_UnPauseEmulation();
		RunIntructions();
#endif

		// Un-init emulation system
		//KillTimer(hWnd,TimerID);
		WinSTon_UnInit();	
	//}

#ifdef TRAP_EXCEP_HISTORY
	// This is called if we got an exception, used in debugging crashes
    __except (ep=GetExceptionInformation()) 
    {
		char szString[1024];

        sprintf(szString,"Exception %08lX at Address %08lX",ep->ExceptionRecord->ExceptionCode,ep->ExceptionRecord->ExceptionAddress);
		M68000_OutputHistory();
        MessageBox(NULL,szString,"Trap",MB_OK);
    }
#endif

	// Close debug files
	ErrLog_CloseFile();
	Debug_CloseFiles();

	// Unregister class
//	if (!hPrevInstance) {
		//UnregisterClass(szName,hInstance);
	//}

	//return(Msg.wParam);
	
return 0 ;

}
