/* Copyright (C) 1994-2003 Revolution Software Ltd
 *
 * 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.
 *
 * $Header$
 */

#define WIN32_LEAN_AND_MEAN

#include "common/stdafx.h"
#include "common/engine.h"
#include "common/timer.h"

#include "driver96.h"

#include "_mouse.h"
#include "keyboard.h"
#include "rdwin.h"
#include "d_draw.h"
#include "palette.h"
#include "render.h"
#include "menu.h"
#include "d_sound.h"
#include "../sword2.h"


#define MENUDEEP 40		// Temporary, until menu.h is written!



//static BOOL		bMouseVisible = FALSE;
//static BOOL		controlKey = FALSE;
//static BOOL		altKey = FALSE;
//static BOOL		wasScreenSaverActive = FALSE;
//static BOOL		myAppClosed = FALSE;
static BOOL		controlQDisabled = FALSE;
//static uint8	gameName[80];


//BOOL			gotTheFocus = FALSE;
//assume we always have focus for the time being - khalek
BOOL			gotTheFocus = TRUE; 
//HWND			hwnd;
//RECT			rcWindow;



//-----------------------------------------------------------------------------

void Zdebug(const char *format,...) {
#ifdef __PALM_OS__
	char buf[256]; // 1024 is too big overflow the stack
#else
	char buf[1024];
#endif
	va_list va;

	va_start(va, format);
	vsprintf(buf, format, va);
	va_end(va);

#ifdef __GP32__ //ph0x FIXME: implement fprint?
	printf("ZDEBUG: %s\n", buf);
#else
	fprintf(stderr, "ZDEBUG: %s!\n", buf);
#endif
#if defined( USE_WINDBG )
	strcat(buf, "\n");
#if defined( _WIN32_WCE )
	TCHAR buf_unicode[1024];
	MultiByteToWideChar(CP_ACP, 0, buf, strlen(buf) + 1, buf_unicode, sizeof(buf_unicode));
	OutputDebugString(buf_unicode);
#else
	OutputDebugString(buf);
#endif
#endif
}

/*
void Zdebug(char *format,...)	//Tony's special debug logging file March96
{
	warning("stub Zdebug");
//	Write a printf type string to a debug file

	va_list		arg_ptr;			// Variable argument pointer
	FILE *		debug_filep=0;			// Debug file pointer
	static int	first_debug = 1;		// Flag for first time this is used

	va_start(arg_ptr,format);

	if (first_debug)					//First time round delete any previous debug file
	{
		unlink("debug.txt");
		first_debug = 0;
	}

	debug_filep = fopen("debug.txt","a+t");

	if (debug_filep != NULL)	// if it could be opened
	{
		vfprintf(debug_filep, format, arg_ptr);
		fprintf(debug_filep,"\n");

		fclose(debug_filep);
	}
}
*/
//-----------------------------------------------------------------------------

/*
void Message(LPSTR fmt, ...)
{
    char	buff[256];
    va_list	va;

    
	va_start(va, fmt);

    //
    // format message with header
    //
    lstrcpy( buff, "DRIVER96:" );
    wvsprintf( &buff[lstrlen(buff)], fmt, va );
    lstrcat( buff, "\r\n" );

    //
    // To the debugger
    //
    OutputDebugString( buff );

}
*/

//-----------------------------------------------------------------------------
//	OSystem Event Handler. Full of cross platform goodness and 99% fat free!
//-----------------------------------------------------------------------------
void Sword2State::parseEvents() {
	OSystem::Event event;
	
	while (_system->poll_event(&event)) {
		switch(event.event_code) {
		
		case OSystem::EVENT_KEYDOWN:
			if (event.kbd.flags==OSystem::KBD_CTRL) {
				if (event.kbd.keycode == 'w')
					GrabScreenShot();
			}
			WriteKey(event.kbd.ascii);
			break;
		case OSystem::EVENT_MOUSEMOVE:
			mousex = event.mouse.x;
			mousey = event.mouse.y - MENUDEEP;
			break;
		case OSystem::EVENT_LBUTTONDOWN:
			LogMouseEvent(RD_LEFTBUTTONDOWN);
			break;
		case OSystem::EVENT_RBUTTONDOWN:
			LogMouseEvent(RD_RIGHTBUTTONDOWN);
			break;
		case OSystem::EVENT_LBUTTONUP:
			LogMouseEvent(RD_LEFTBUTTONUP);
			break;
		case OSystem::EVENT_RBUTTONUP:
			LogMouseEvent(RD_RIGHTBUTTONUP);
			break;
		case OSystem::EVENT_QUIT:
			Close_game();
			CloseAppWindow();
			break;
		default:
			break;
		}
	}
		
}


//-----------------------------------------------------------------------------
//	Windows Message Handler.  All keyboard and mouse input is handled here.
//-----------------------------------------------------------------------------
/*
long FAR PASCAL WindowsMessageHandler(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{

	switch( message )
	{


	case WM_TIMER:
		switch (wParam)
		{
		case 25:
			FadeServer();
			return(0);
		case 1:
			FxServer();
			return(0);
		}
		break;
		

    case WM_CLOSE:
		Zdebug("WM_CLOSE");
		break;

    case WM_SIZE:
    case WM_MOVE:
        if (IsIconic(hwnd))
        {
            Message("minimising");
//            PauseGame();
        }

        if (bFullScreen)
        {
            SetRect(&rcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
        }
        else
        {
            GetClientRect(hwnd, &rcWindow);
            ClientToScreen(hwnd, (LPPOINT)&rcWindow);
            ClientToScreen(hwnd, (LPPOINT)&rcWindow+1);
        }
        Message("WINDOW RECT: [%d,%d,%d,%d]", rcWindow.left, rcWindow.top, rcWindow.right, rcWindow.bottom);
		if (bFullScreen)
		{
			SetCapture(hwnd);
		}
		else
		{
			ReleaseCapture();
		}
//		SetCursor(NULL);
//		ShowCursor(FALSE);
        break;



	case WM_ACTIVATEAPP:
		gotTheFocus = wParam;
		if (gotTheFocus)
		{
			Message("Got the focus");
			bMouseVisible = FALSE;
			Message("Mouse invisible");
			ShowCursor(FALSE);
		}
		else
		{
			if (bMouseVisible == FALSE)
				ShowCursor(TRUE);
			Message("Lost the focus");
			bMouseVisible = TRUE;
			Message("Mouse visible");
		}
		break;


    case WM_SYSKEYUP:
        switch( wParam )
        {

//			int32 rv;

        // handle ALT+ENTER (fullscreen)
        case VK_RETURN:
			break;
        }
        break;
 

	case WM_DISPLAYCHANGE:
		break;

	case WM_CREATE:
		SystemParametersInfo(SPI_GETSCREENSAVEACTIVE , 0 , &wasScreenSaverActive , 0);
		if (wasScreenSaverActive)
		{
			SystemParametersInfo(SPI_SETSCREENSAVEACTIVE , FALSE , 0 , 0 );
		}
    	break;


    case WM_QUERYNEWPALETTE:
        //
        //  we are getting the palette focus, select our palette
        //
        if (!bFullScreen && lpPalette && lpPrimarySurface)
        {
			int32 hr;

            hr = IDirectDrawSurface_BS2_SetPalette(lpPrimarySurface, lpPalette);
            if (hr == DDERR_SURFACELOST)
            {
                IDirectDrawSurface_Restore(lpPrimarySurface);

                hr= IDirectDrawSurface_BS2_SetPalette(lpPrimarySurface, lpPalette);
                if(hr == DDERR_SURFACELOST)
                {
                   Message("Failed to restore palette after second try");
                }
            }

            //
            // Restore normal title if palette is ours
            //
            if(hr == DD_OK)
            {
                SetWindowText(hwnd, gameName);
            }
        }
        break;

    case WM_PALETTECHANGED:
        //
        //  if another app changed the palette we dont have full control
        //  of the palette. NOTE this only applies for FoxBear in a window
        //  when we are fullscreen we get all the palette all of the time.
        //
        if ((HWND)wParam != hwnd)
        {
            if( !bFullScreen )
            {
				Message("Lost palette but continuing");
            }
        }
        break;


//    case WM_SETCURSOR:
//		if (bMouseVisible)
//			SetCursor(LoadCursor(NULL, IDC_ARROW));
//		else
//			SetCursor(NULL);
//	    return TRUE;
//		break;

	case WM_CHAR:
		if (lParam & (1 << 30))
			return(0);
		WriteKey((char) (wParam & 0xff));
		return(0);

    case WM_KEYDOWN:

		Zdebug("key %d", wParam);

		switch( wParam )
		{
			case VK_CONTROL:
				controlKey = TRUE;
				break;

//			case VK_ALT:
//				altKey = TRUE;
//				break;

			case 'W':
				if (controlKey)
					GrabScreenShot();
				return 0;

			case 'Q':
				if (controlKey && !controlQDisabled)
					DestroyWindow( hWnd );
  				return 0;

			case 'F4':
				DestroyWindow( hWnd );
  				return 0;

        }
      	break;


	case WM_KEYUP:
		switch(wParam)
		{
			case VK_CONTROL:
				controlKey = FALSE;
				break;

//			case VK_ALT:
//				altKey = FALSE;
//				break;

		}
	    break;


    case WM_DESTROY:
		Zdebug("*destroy*");

		if (wasScreenSaverActive)
			SystemParametersInfo(SPI_SETSCREENSAVEACTIVE , TRUE , 0 , 0 );
        PostQuitMessage( 0 );
        break;


	case WM_MOUSEMOVE:
		mousex = lParam & 0xffff;

		if (bFullScreen)
		{
			mousey = (uint16) (lParam >> 16) - MENUDEEP;
		}
		else
		{
			mousey = (uint16) (lParam >> 16) - MENUDEEP;

			if (mousex < 0)
				mousex = 0;
			if (mousex >= RENDERWIDE)
				mousex = RENDERWIDE-1;
		}

		if (mousey < -MENUDEEP)
			mousey = -MENUDEEP;
		if (mousey >= RENDERDEEP + MENUDEEP)
			mousey = RENDERDEEP + MENUDEEP - 1;

		return(0);

	case WM_LBUTTONDOWN:
		LogMouseEvent(RD_LEFTBUTTONDOWN);
		return(0);

	case WM_LBUTTONUP:
		LogMouseEvent(RD_LEFTBUTTONUP);
		return(0);

	case WM_RBUTTONDOWN:
		LogMouseEvent(RD_RIGHTBUTTONDOWN);
		return(0);

	case WM_RBUTTONUP:
		LogMouseEvent(RD_RIGHTBUTTONUP);
		return(0);

	case WM_LBUTTONDBLCLK:
		LogMouseEvent(RD_LEFTBUTTONDOWN);
		return(0);
		
	case WM_RBUTTONDBLCLK:
		LogMouseEvent(RD_RIGHTBUTTONDOWN);


	case WM_SYSCOMMAND:
		if (gotTheFocus)
			return(0);




	}

	return DefWindowProc(hWnd, message, wParam, lParam);

}
*/


/*
int32 InitialiseWindow(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow, char *gameName)

{
	
	WNDCLASS    wc;
//	uint32		err;


//	hPrevInstance = hPrevInstance;
	wc.style = CS_DBLCLKS;
	wc.lpfnWndProc = WindowsMessageHandler;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hIcon = LoadIcon( hInstance, "resourc1");  //IDI_APPLICATION );
	wc.hCursor = LoadCursor( NULL, IDC_ARROW );
	wc.hbrBackground = GetStockObject(BLACK_BRUSH);

	wc.lpszMenuName = gameName;
	wc.lpszClassName = gameName;

	RegisterClass( &wc );

	// Create a window
	hwnd = CreateWindowEx(WS_EX_APPWINDOW, gameName, gameName, WS_VISIBLE | WS_SYSMENU | WS_POPUP, 0, 0,
			GetSystemMetrics( SM_CXSCREEN ), GetSystemMetrics( SM_CYSCREEN ),
			NULL, NULL, hInstance, NULL );

	if(!hwnd)
	{
	    MessageBox(hwnd, "Failed to create window", gameName, MB_OK );
	    DestroyWindow(hwnd);
		return(RDERR_CREATEWINDOW);
	}

//	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);
	SetFocus(hwnd);
	
	SetTimer(hwnd, 25, 1000 / 25, NULL);
	SetTimer(hwnd, 1, 100, NULL);

	return(RD_OK);

}
*/


int32 CloseAppWindow(void)

{
	warning("stub CloseAppWindow");
/*
	DestroyWindow(hwnd);
*/
	// just quit for now
	g_engine->_timer->releaseProcedure(sword2_sound_handler);
	g_system->quit();
	return(RD_OK);

}

static bool _needRedraw = false;

void SetNeedRedraw() {
	_needRedraw = true;
}

int32 ServiceWindows(void)

{
	g_sword2->parseEvents();
	FadeServer();

	// FIXME: We re-render the entire picture area of the screen for each
	// frame, which is pretty horrible.

	if (_needRedraw) {
		g_system->copy_rect(lpBackBuffer + MENUDEEP * screenWide, screenWide, 0, MENUDEEP, screenWide, screenDeep - 2 * MENUDEEP);
		_needRedraw = false;
	}

	// We still need to update because of fades, menu animations, etc.
	g_system->update_screen();

//	warning("stub ServiceWindows");  // too noisy
/*
	MSG msg;

	if (myAppClosed)
		return(RDERR_APPCLOSED);

	while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
	{
		if (!GetMessage(&msg, NULL, 0, 0))
		{
			myAppClosed = TRUE;
			return(RDERR_APPCLOSED);
		}

		TranslateMessage(&msg);
		DispatchMessage(&msg);
  	}
*/
	return(RD_OK);

}




int32 _ReportDriverError(int32 error, const uint8 *filename, uint32 line)

{
	warning("stub _ReportDriverError 0x%.8x file: %s, line: %d ", error, (const char *) filename, line);
/*

	char errorText[128];
	char name[80];


	GetGameName(name);
	sprintf(errorText, "Fatal error in %s, line %u!  Code 0x%.8x", filename, line, error);
    MessageBox(hwnd, errorText, name, MB_SYSTEMMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE);
*/	
	return(RD_OK);

}



int32 _ReportFatalError(const uint8 *error, const uint8 *filename, uint32 line)

{

	warning("stub _ReportFatalError");
	char errorText[500];
	char name[80];


	GetGameName((uint8 *)name);
	sprintf(errorText, "FATAL ERROR - GAME TERMINATED\n%s", error);
	//MessageBox(hwnd, errorText, name, MB_SYSTEMMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE);
	warning("%s", errorText);

	return(RD_OK);

}


int32 DisableQuitKey(void)
{
	controlQDisabled = TRUE;
	return(RD_OK);
}

void SetWindowName(const char *windowName)
{
	warning("stub SetWindowName( %s )", windowName);
//	SetWindowText(hwnd,windowName);
//	strcpy(gameName,windowName);
}