#include <stdint.h>
#include <stdio.h>
#include <windows.h>
#include "gba.h"
#include "resources.h"

int infocus,drawit;
int running;

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
char szClassName[ ] = "WindowsApp";

HWND ghwnd;
HINSTANCE hinstance;

int gbaclose=0;
int gbapause=0,gbawaiting=0;
void _mainthread(PVOID pvoid)
{
        while (1)
        {
                if (gbapause || !infocus)
                {
                        gbawaiting=1;
                        sleep(100);
                }
                else
                {
                        gbawaiting=0;
                        if (running) rungba();
                }
        }
}

CRITICAL_SECTION cs;

void startblit()
{
        EnterCriticalSection(&cs);
}

void endblit()
{
        LeaveCriticalSection(&cs);
}

HANDLE mainthread;

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nFunsterStil)

{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */
    int c,d;
    FILE *f;
    int oldinfocus=0;
    int quited=0;

        hinstance=hThisInstance;
    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default color as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "reasonableGBA v0.2",       /* Title Text */
           WS_OVERLAPPEDWINDOW&~WS_SIZEBOX, /* default window */
           CW_USEDEFAULT,       /* Windows decides the position */
           CW_USEDEFAULT,       /* where the window ends up on the screen */
           480+(GetSystemMetrics(SM_CXFIXEDFRAME)*2),                 /* The programs width */
           320+(GetSystemMetrics(SM_CYFIXEDFRAME)*2)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+1,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           LoadMenu(hThisInstance,TEXT("MainMenu")),                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

        /* Make the window visible on the screen */
        ShowWindow (hwnd, nFunsterStil);

        win_set_window(hwnd);

        ghwnd=hwnd;

        initgba();
        c=loadbios();
        if (c)
        {
                MessageBox(NULL,"BIOS file not found!\nMust be bios.rom and in the reasonableGBA directory","Critical Error",MB_OK);
                return -1;
        }

        infocus=1;
        running=0;
        scale=2;
        
        InitializeCriticalSection(&cs);
        mainthread=(HANDLE)_beginthread(_mainthread,0,NULL);
        
        while (!quited)
        {
/*                if (infocus)
                {
                        if (running) rungba();
                }*/

                if (PeekMessage(&messages,NULL,0,0,PM_REMOVE))
                {
                        if (messages.message==WM_QUIT)
                           quited=1;
                        /* Translate virtual-key messages into character messages */
                        TranslateMessage(&messages);
                        /* Send message to WindowProcedure */
                        DispatchMessage(&messages);
                }
                sleep(10);
        }
        
        EnterCriticalSection(&cs);
        sleep(100);
        TerminateThread(mainthread,0);
        endgba();
        DeleteCriticalSection(&cs);

        return 0;
}

char openfilestring[260];

int getfile(HWND hwnd, char *f, char *fn)
{
        OPENFILENAME ofn;       // common dialog box structure
        char szFile[260];       // buffer for file name

        // Initialize OPENFILENAME
        ZeroMemory(&ofn, sizeof(ofn));
        ofn.lStructSize = sizeof(ofn);
        ofn.hwndOwner = hwnd;
        ofn.lpstrFile = openfilestring;
        //
        // Set lpstrFile[0] to '\0' so that GetOpenFileName does not
        // use the contents of szFile to initialize itself.
        //
//        ofn.lpstrFile[0] = '\0';
        strcpy(ofn.lpstrFile,fn);
        ofn.nMaxFile = sizeof(openfilestring);
        ofn.lpstrFilter = f;//"All\0*.*\0Text\0*.TXT\0";
        ofn.nFilterIndex = 1;
        ofn.lpstrFileTitle = NULL;
        ofn.nMaxFileTitle = 0;
        ofn.lpstrInitialDir = NULL;
        ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

        // Display the Open dialog box.

        if (GetOpenFileName(&ofn))
        {
                strcpy(fn,ofn.lpstrFile);
                return 0;
        }
        return 1;
}


void getromname()
{
        if (getfile(NULL,"GBA ROM (*.gba)\0*.GBA\0All Files (*.*)\0*.*\0\0",romname))
           exit(-1);
}

void updatewindowsize(int x, int y)
{
        RECT r;
        GetWindowRect(ghwnd,&r);
        MoveWindow(ghwnd,r.left,r.top,
                     x+(GetSystemMetrics(SM_CXFIXEDFRAME)*2),
                     y+(GetSystemMetrics(SM_CYFIXEDFRAME)*2)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+1,
                     TRUE);
}

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        HMENU hmenu;
        switch (message)
        {
                case WM_COMMAND:
                hmenu=GetMenu(hwnd);
                switch (LOWORD(wParam))
                {
                        case IDM_FILE_LOAD:
                        startblit();
                        sleep(100);
                        loadgba();
                        running=1;
                        drawit=0;
                        endblit();
                        break;
                        case IDM_FILE_RESET:
                        startblit();
                        sleep(100);
                        resetgba();
                        drawit=0;
                        endblit();
                        break;
                        case IDM_FILE_EXIT:
                        PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
                        break;
                        case IDM_SCALE_1: case IDM_SCALE_2:
                        case IDM_SCALE_3: case IDM_SCALE_4:
                        scale=(LOWORD(wParam)-IDM_SCALE_1)+1;
                        updatewindowsize(240*scale,160*scale);
                        drawit=0;
                        break;
                        case IDM_SCALE_2XSAI: case IDM_SCALE_EAGLE:
                        scale=(LOWORD(wParam)-IDM_SCALE_2XSAI)+0x80;
                        updatewindowsize(480,320);
                        drawit=0;
                        break;
                }
                return 0;

                case WM_SETFOCUS:
                infocus=1;
                drawit=0;
                break;
                
                case WM_KILLFOCUS:
                infocus=0;
                break;
                
                case WM_DESTROY:
                PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
                break;
                default:
                return DefWindowProc (hwnd, message, wParam, lParam);
        }
        return 0;
}
