#include <windows.h>
#include <windowsx.h>
#include <tchar.h>
#include "ClockManager.h"
#include "../source/cartridge.h"
#include "../source/GBMachine.h"
#include "DIB.h"
#include "resource.h"
#include "../source/gameboy.h"

#define szTitle				_T("NomadGB main window")
#define szWindowClass		_T("NomadGB")
#define BACKGROUND_COLOR	RGB(0,0,0)

//#define WIN_SIZE			2

#define WINDOWED_APP		1
#define WINDOW_WIDTH		160//*WIN_SIZE
#define WINDOW_HEIGHT		144//*WIN_SIZE

HDC			g_hdc;
HWND		main_window_handle;
HINSTANCE	hInst;
CCartridge	g_Cart;
CDIB		g_dib;
u32			g_Key[4];

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

void GameInit();
void GameLoop();
u32 UpdateKeyState();
void DumpInfo();

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	MSG msg;
	//HACCEL hAccelTable;
	
	//////////////////////////////////////////////////////////////////////////
	//Register Class
	HBRUSH hbkbrush=CreateSolidBrush(BACKGROUND_COLOR);
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX); 

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= (WNDPROC)WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= NULL;//LoadIcon(hInstance, (LPCTSTR)IDI_DENGINE);
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= hbkbrush;//(HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDR_MENU_MAIN);//(LPCTSTR)IDR_MENU_MAIN;
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= NULL;//LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);

	RegisterClassEx(&wcex);

	//////////////////////////////////////////////////////////////////////////
	//Create Window

	HWND hWnd;

	hInst = hInstance; // Store instance handle in our global variable

	hWnd = CreateWindow(szWindowClass, szTitle, (WINDOWED_APP ? (WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION) : (WS_POPUP | WS_VISIBLE)),//WS_OVERLAPPEDWINDOW,
		0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);

// 	if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME, // class
// 		WINDOW_TITLE,	 // title
// 		(WINDOWED_APP ? (WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION) : (WS_POPUP | WS_VISIBLE)),
// 		0,0,	   // x,y
// 		WINDOW_WIDTH,  // width
// 		WINDOW_HEIGHT, // height
// 		NULL,	   // handle to parent 
// 		NULL,	   // handle to menu
// 		hinstance,// instance
// 		NULL)))	// creation parms
// 		return(0);

	if (!hWnd)
	{
		return FALSE;
	}

	main_window_handle=hWnd;
	g_hdc=GetDC(main_window_handle);

	if (WINDOWED_APP)
	{
		RECT window_rect = {0,0,WINDOW_WIDTH-1,WINDOW_HEIGHT-1};
		//HWND main_window_handle = hWnd;

		AdjustWindowRectEx(&window_rect,
			GetWindowStyle(main_window_handle),
			GetMenu(main_window_handle) != NULL,
			GetWindowExStyle(main_window_handle));
		/*
		MoveWindow(main_window_handle,
		0, // x position
		0, // y position
		window_rect.right - window_rect.left+1, // width
		window_rect.bottom - window_rect.top+1, // height
		FALSE);
		*/
		::SetWindowPos(main_window_handle,HWND_NOTOPMOST,100,100,window_rect.right - window_rect.left+1,window_rect.bottom - window_rect.top+1,SWP_NOOWNERZORDER);

	} 

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	//hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_DENGINE);

	//////////////////////////////////////////////////////////////////////////
	//SystemParametersInfo(SPI_SCREENSAVERRUNNING, TRUE, NULL, 0);

	GameInit();

	while(1)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
		{ 
			if (msg.message == WM_QUIT) 
				break; 
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		} 
		GameLoop();
	}

	//GameShutdown();
	//SystemParametersInfo(SPI_SCREENSAVERRUNNING, FALSE, NULL, 0);
	return (int) msg.wParam;
}


LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId,wmEvent;
	
	switch (message) 
	{
	case WM_CREATE:
#ifdef PIXEL_FORMAT565
		g_dib.Create(WINDOW_WIDTH,-WINDOW_HEIGHT,16,DIB_PIXEL_FORMAT16_565);//???????,??????DIB
#else
		g_dib.Create(WINDOW_WIDTH,-WINDOW_HEIGHT,16,DIB_PIXEL_FORMAT16_555);
#endif
		break;
	case WM_KEYDOWN:
		switch(wParam)
		{
		case VK_LEFT:
			g_Key[0] |= NMGB_KEY_LEFT;
			break;
		case VK_RIGHT:
			g_Key[0] |= NMGB_KEY_RIGHT;
			break;
		case VK_UP:
			g_Key[0] |= NMGB_KEY_UP;
			break;
		case VK_DOWN:
			g_Key[0] |= NMGB_KEY_DOWN;
			break;
		case VK_RETURN:
			g_Key[0] |= NMGB_KEY_START;
			break;
		case VK_SPACE:
			g_Key[0] |= NMGB_KEY_SELECT;
			break;
		case 'X':case 'x':
			g_Key[0] |= NMGB_KEY_A;
			break;
		case 'Z':case 'z':
			g_Key[0] |= NMGB_KEY_B;
			break;
		case VK_F5:
			DumpInfo();
		default:
			break;
		}
		break;
	case WM_KEYUP:
		switch(wParam)
		{
		case VK_LEFT:
			g_Key[0] &= ~NMGB_KEY_LEFT;
			break;
		case VK_RIGHT:
			g_Key[0] &= ~NMGB_KEY_RIGHT;
			break;
		case VK_UP:
			g_Key[0] &= ~NMGB_KEY_UP;
			break;
		case VK_DOWN:
			g_Key[0] &= ~NMGB_KEY_DOWN;
			break;
		case VK_RETURN:
			g_Key[0] &= ~NMGB_KEY_START;
			break;
		case VK_SPACE:
			g_Key[0] &= ~NMGB_KEY_SELECT;
			break;
		case 'X':case 'x':
			g_Key[0] &= ~NMGB_KEY_A;
			break;
		case 'Z':case 'z':
			g_Key[0] &= ~NMGB_KEY_B;
			break;
		default:
			break;
		}
		break;
	case WM_SIZE:
		{
			RECT rt1;
			GetWindowRect(hWnd,&rt1);
			//rt1.right=rt1.left+SCREEN_WIDTH;
			//rt1.bottom=rt1.top+SCREEN_HEIGHT;
			//SetWindowPos(hWnd,HWND_TOP,rt1.left,rt1.top,SCREEN_WIDTH,SCREEN_HEIGHT,SWP_SHOWWINDOW);
		}
		break;
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// Parse the menu selections:
		switch (wmId)
		{
// 		case IDM_ABOUT:
// 			DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About);
// 			break;
// 		case IDM_EXIT:
// 			DestroyWindow(hWnd);
// 			break;
		case ID_FILE_EXIT:
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
		case WM_PAINT:
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

void GameInit()
{
	//(_T("Soukoban 2 (Japan).gb"));//(_T("Tetris.gb"));////(_T("King of Fighters, The - Heat of Battle (Europe).gb"));//(_T("Takahashi Meijin no Boukenjima II (Japan).gb"));//(_T("Soukoban (Japan).gb"));//(_T("Doraemon no Study Boy 5 - Shou 2 Sansuu Keisan (Japan).gb"));//
	g_Cart.LoadRomFile(_T("Kwirk (USA, Europe).gb"));//(_T("Star Ocean - Blue Sphere.gbc"));//(_T("GB1243_migongzuqu.GB"));//(_T("Tenchi o Kurau (Japan).gb"));//(_T("Legend of Zelda, The - Link's Awakening (USA, Europe).gb"));//(_T("Baseball (World).gb"));//(_T("xiao mei ren yu.GB"));//(_T("Saint Paradise - Saikyou no Senshi-tachi (Japan).gb"));//(_T("gb2010(A lei sha 1).GB"));//(_T("gb2115(A lei sha 3).GB"));
		//(_T("SAGA3.GB"));//(_T("Taiyou no Tenshi Marlowe - Ohanabatake ha Dai-Panic (J).gb"));//(_T("Monster Max (U).gb"));//(_T("Final Fantasy Legend, The (USA).gb"));//(_T("Super Robot Taisen (Japan).gb"));//(_T("Nettou The King of Fighters '95 (Japan).gb"));//(_T("Super Mario Land (World).gb"));//(_T("Wario Land - Super Mario Land 3 (World).gb"));//(_T("Vitamina Oukoku Monogatari (Japan).gb"));//(_T("Seiken Densetsu (Japan).gb"));//(_T("Captain Tsubasa VS (Japan).gb"));//
	g_pGameBoy->m_pFrameBuffer[0] = (u16*)g_dib.GetBits();
	g_pGameBoy->m_pFrameBuffer[1] = (u16*)g_dib.GetBits();
}

bool FB_OK = false;

void GameLoop()
{
	Start_Clock();
	
	u8* buf = (u8*)g_pGameBoy->m_pFrameBuffer[g_pGameBoy->m_nCurFrame];
	memset(buf, 0, WINDOW_WIDTH*WINDOW_HEIGHT*2);


	//u32 ks = UpdateKeyState();
	g_pGameBoy->SetKeyState(0, /*ks*/g_Key[0]);

	while(!FB_OK)
		g_pGameBoy->Start();

	FB_OK = false;	

	g_dib.BitBlt(g_hdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,0,0);

	Wait_Clock(FPS_60);
}

u32 UpdateKeyState()
{
	return g_Key[0];
}

void DumpInfo()
{
	g_pGameBoy->GetMemory()->DumpDebugInfo();
}