/*
 * FrotzCEOS.cpp
 *
 * Windows CE Frotz OS interface
 *
 */

#include "StdAfx.h"

#include "FrotzCE.h"
#include "MainFrm.h"
#include "FrotzCEDoc.h"
#include "FrotzCEView.h"
#include "StoryInfo.h"

static BOOL bWasUsingColours;
static int nOldFontHeight;
static int nOldFontWidth;

extern "C" 
{
#include "Frotz/frotz.h"

extern char euro_substitute[];

void 	os_draw_picture (int n, int x, int y) {}
void 	os_finish_with_sample (void) {}
int  	os_font_data (int n, int *height, int *width) { return 0; }
int  	os_peek_colour (void) { return 0; }
int  	os_picture_data (int n, int *height, int *width) { return 0; }
void	os_process_arguments (int argc, char *argv[]) {}
void 	os_prepare_sample (int n) {}
void 	os_set_font (int font) {}
void 	os_start_sample (int n, int r, int vol) {}
void 	os_stop_sample (void) {}
void 	os_wait_sample (void) {}
}

extern StoryInfo acInfocomReleases[NO_INFOCOM_STORIES];

extern "C" void os_beep (int n) 
{
	// Produce a beep
	::MessageBeep( 0xFFFFFFFF );
}

extern "C" int os_char_width (int c)
{
	// Gap between sentences?
    if (c == 9)	return 2;
	// Paragraph indentation?
    else if (c == 11) return 3;
	// European char?
    else if (FROTZCEAPP->m_bUseEuroChars && c >= EURO_MIN && c <= EURO_MAX)
	{
		return (euro_substitute[2 * (c - EURO_MIN) + 1] == ' ') ? 1 : 2;
	}
    else return 1;
}

extern "C" void os_cursor_off (void) 
{
	// Turn off cursor
	FROTZCEVIEW->SetCursorState( FALSE );
}

extern "C" void os_cursor_on (void) 
{
	// Turn on cursor
	FROTZCEVIEW->SetCursorState( TRUE );
}

extern "C" void os_display_char (int c)
{
	// European char?
    if (FROTZCEAPP->m_bUseEuroChars && c >= EURO_MIN && c <= EURO_MAX)
	{
	int c1 = euro_substitute[2 * (c - EURO_MIN)];
	int c2 = euro_substitute[2 * (c - EURO_MIN) + 1];

	    os_display_char( c1 );

	    if (c2 != ' ') c = c2;
	    else return;

	}

	// Display char and update screen
	FROTZCEVIEW->DisplayChar( (char) c );
}

extern "C" void os_display_string (const char *s)
{
	// Display string
	FROTZCEVIEW->DisplayString( s );
}

extern "C" void os_erase_area (int top, int left, int bottom, int right) 
{
	// Erase specified screen area
	FROTZCEVIEW->EraseScreenArea( --top, --left, --bottom, --right );
}

extern "C" void os_fatal (const char *s)
{
CString strError = s;

	// Display error
	AfxMessageBox( strError );

	// Z machine running?
	if (FROTZCEAPP->m_bZmachineRunning)
	{
		// Reset memory
		reset_memory ();

		// Flag that Z machine is no longer running
		FROTZCEAPP->m_bZmachineRunning = FALSE;

		// Reset display
		os_reset_screen ();
	}

	// Stop execution of Z machine thread 
	AfxEndThread(1);
}

extern "C" void os_init_screen (void)
{
	// Save current settings
	bWasUsingColours = FROTZCEAPP->m_bUseColours;
	nOldFontHeight = FROTZCEAPP->m_nFontHeight;
	nOldFontWidth = FROTZCEAPP->m_nFontWidth;

	// Try to recognise story
	for (int nStoryNo = 0; nStoryNo < NO_INFOCOM_STORIES; nStoryNo++)
	{
		// Found story information?
		if (acInfocomReleases[nStoryNo].nRelease == h_release
			&& strcmp( acInfocomReleases[nStoryNo].achSerialNo, (char *) h_serial ) == 0)
		{
		CString strStoryName = acInfocomReleases[nStoryNo].achStoryName;

			// Check if story is supported
			if ((acInfocomReleases[nStoryNo].nSettings & STORY_NOSUPPORT) != 0)
			{
			CString strDisplay = strStoryName + TEXT( " is not supported by FrotzCE" );

				// Display message
				AfxMessageBox( strDisplay );
				return;
			}

			// Check if story is supported
			if ((acInfocomReleases[nStoryNo].nSettings & STORY_LIMITEDSUPPORT) != 0)
			{
			CString strDisplay = strStoryName 
				+ TEXT( " is not properly supported by FrotzCE" );

				// Display message
				AfxMessageBox( strDisplay );
			}

			// Story requires small font?
			if ((acInfocomReleases[nStoryNo].nSettings & STORY_SMALLFONT) != 0
				&& FROTZCEAPP->m_nFontHeight == 0)
			{
				FROTZCEAPP->m_nFontHeight = TERMINAL_FONT_HEIGHT;
				FROTZCEAPP->m_nFontWidth = TERMINAL_FONT_WIDTH;
			}

			// Story requires small font?
			if ((acInfocomReleases[nStoryNo].nSettings & STORY_NOCOLOURS) != 0)
			{
				FROTZCEAPP->m_bUseColours = FALSE;
			}

			// Story uses graphics chars?
			if ((acInfocomReleases[nStoryNo].nSettings & STORY_GFXCHARS) != 0)
			{
				FROTZCEAPP->m_bUseEuroChars = FALSE;
			}

			// Set window title
			MAINFRAME->SetWindowText( strStoryName );
			break;
		}
	}

	// Update menus
	MAINFRAME->SendMessage( WM_UPDATE_MENU );
	  
	// Initialise screen
	FROTZCEVIEW->InitialiseScreen();

	// Set screen dimensions
    h_screen_width = h_screen_cols = FROTZCEVIEW->GetWidth();
    h_screen_height = h_screen_rows = FROTZCEVIEW->GetHeight();

	// Set config flags
    if (h_version == V3 && FROTZCEAPP->m_bTandy)
		h_config |= CONFIG_TANDY;

	if (h_version == V3)
		h_config |= CONFIG_SPLITSCREEN;
		  
	if (h_version >= V4)
	{
		h_config |= CONFIG_FIXED | CONFIG_TIMEDINPUT;

		if (FROTZCEAPP->m_bUseStyles)
			h_config |= CONFIG_BOLDFACE | CONFIG_EMPHASIS;
	}
	
	if (h_version >= V5 && FROTZCEAPP->m_bUseColours)
		h_config |= CONFIG_COLOUR;
		  
	/* Handle various game flags. These flags are set if the game wants
	to use certain features. The flags must be cleared if the feature
	is not available. */
		  
	if (h_flags & GRAPHICS_FLAG)
		h_flags &= ~GRAPHICS_FLAG;
		  
	if (h_version == V3 && (h_flags & OLD_SOUND_FLAG))
		h_flags &= ~OLD_SOUND_FLAG;
		  
	if (h_flags & SOUND_FLAG)
		h_flags &= ~SOUND_FLAG;
		  
	if (h_flags & MOUSE_FLAG)
		h_flags &= ~MOUSE_FLAG;

	h_flags &= ~MENU_FLAG;
		  
	/* Set the interpreter number (a constant telling the game which
	operating system it runs on) and the interpreter version. The
	interpreter number has effect on all V6 games and Beyond Zork. */
		  
	h_interpreter_number = INTERP_MSDOS;
	h_interpreter_version = 'E';

	// Show cursor
	os_cursor_on();

	// Flag that initialised
	FROTZCEAPP->m_bInitialised = TRUE;
}

extern "C" void os_more_prompt (void) 
{
int nRow, nCol;

	// Save cursor position
	FROTZCEVIEW->GetCursorPos( &nRow, &nCol );

	// Hide cursor
	os_cursor_off();

	// Display prompt
	os_set_text_style( REVERSE_STYLE );
	os_display_string( "[MORE]" );
	os_set_text_style( NORMAL_STYLE );
	os_read_key( 0 );

	// Show cursor
	os_cursor_on();

	// Remove prompt
	FROTZCEVIEW->SetCursorPos( nRow, nCol );
	os_display_string( "      " );
	FROTZCEVIEW->SetCursorPos( nRow, nCol );
}

extern "C" int os_random_seed (void) 
{ 
CTime cTime = CTime::GetCurrentTime();	

	// Return current time as random seed
	return (int) cTime.GetTime();
}

extern "C" int os_read_file_name (char *name, const char *default_name, int type)
{
CString strFileName = default_name;
CString strDefDir = FROTZCEAPP->m_strDefaultDir, strFilter;
// Set up file filter and set up file dialog
CFileDialog dlgFile( TRUE, NULL, (LPCTSTR) strFileName, 0, 
	 TEXT( "All Files (*.*)|*.*||" ), AfxGetMainWnd() );
int nReturn = 1;

	// Hide cursor
	os_cursor_off();


	// Set initial directory
	dlgFile.m_ofn.lpstrInitialDir = strDefDir.GetBuffer( strDefDir.GetLength() + 1 );

	// Process file dialog
	if (dlgFile.DoModal() == IDOK)
	{
	LPTSTR pszDefDir;
	int i;

		// Get file name from dialog
		strFileName = dlgFile.GetPathName();

		// Copy file name
		strDefDir.ReleaseBuffer();
		strDefDir = strFileName;
		// Go backwards in file name until first '\' is found
		i = strDefDir.GetLength();
		for (pszDefDir = strDefDir.GetBuffer( i + 1 ); i >= 0; i--)
		{
			// Not a directory specifier?
			if (pszDefDir[i] != _T('\\') && pszDefDir[i] != _T('/'))
			{
				// Erase it
				pszDefDir[i] = 0;
			}
			else 
			{
				if (i != 0) pszDefDir[i] = 0;
				break;
			}
		}
		// Resize string
		strDefDir.ReleaseBuffer();

		// Save it
		FROTZCEAPP->m_strDefaultDir = strDefDir;

		// Convert wide char file name to single byte chars
		for (i = 0; i < strFileName.GetLength(); i++)
		{
			name[i] = (char) strFileName[i];
		}
		name[strFileName.GetLength()] = '\0';
	}
	else 
	{
		strDefDir.ReleaseBuffer();
		nReturn = 0;
	}

	// Make sure we've still got the focus
	FROTZCEVIEW->SendMessage( WM_TAKE_FOCUS );

	// Show cursor
	os_cursor_on();

    return nReturn;
}

extern "C" int os_read_key (int timeout)
{
	// Get a keypress
	return FROTZCEVIEW->GetKey( timeout );
}

extern "C" int os_read_line (int max, char *buf, int timeout, int width, int continued)
{
	// Get a line from the keyboard
	return FROTZCEVIEW->GetLine( buf, max, timeout );
}

extern "C" void os_reset_screen (void) 
{
	// Clear screen
	FROTZCEVIEW->ClearScreen( TRUE );

	// Turn off cursor
	os_cursor_off();

	// Reset screen
	FROTZCEVIEW->ResetScreen();

	// Close document
	FROTZCEVIEW->GetDocument()->OnNewDocument();

	// Update menus
	MAINFRAME->SendMessage( WM_UPDATE_MENU );

	// Set window title
	MAINFRAME->SetWindowText( TEXT( "FrotzCE" ) );

	// Flag that not initialised
	FROTZCEAPP->m_bInitialised = FALSE;

	// Restore previous settings
	FROTZCEAPP->m_bUseEuroChars = TRUE;
	FROTZCEAPP->m_bUseColours = bWasUsingColours;
	FROTZCEAPP->m_nFontHeight = nOldFontHeight;
	FROTZCEAPP->m_nFontWidth = nOldFontWidth;
}

extern "C" void os_scroll_area (int top, int left, int bottom, int right, int units)
{
	// Scroll an area of the screen
	FROTZCEVIEW->ScrollScreenArea( --top, --left, --bottom, --right, units );
}

extern "C" void os_set_colour (int fg, int bg) 
{
	FROTZCEVIEW->SetTextColour( fg, bg );
}

extern "C" void os_set_cursor (int y, int x) 
{
	// Set the cursor position
	FROTZCEVIEW->SetCursorPos( --y, --x );
}

extern "C" void	os_set_text_style (int style) 
{
	// Set the text style
	FROTZCEVIEW->SetTextStyle( style );
}

extern "C" int os_string_width (const char *s)
{
int width;

	// Process string
    for (width = 0; *s; s++) 
	{
		if (*s != NEW_FONT && *s != NEW_STYLE)
		{
			// Get width of character
			width += os_char_width ((unsigned char) *s);
		}
		else s++;
    }

    return width;
}
