#ifndef SRC_WX_APP_H_
#define SRC_WX_APP_H_

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif

#include "wx-utils.h"

class CallbackEvent;
class PopupMenuEvent;

wxDECLARE_EVENT(WX_CALLBACK_EVENT, CallbackEvent);
wxDECLARE_EVENT(WX_EXIT_EVENT, wxCommandEvent);
wxDECLARE_EVENT(WX_STOP_EMULATION_EVENT, wxCommandEvent);
wxDECLARE_EVENT(WX_STOP_EMULATION_NOW_EVENT, wxCommandEvent);
wxDECLARE_EVENT(WX_EXIT_COMPLETE_EVENT, wxCommandEvent);
wxDECLARE_EVENT(WX_SHOW_WINDOW_EVENT, wxCommandEvent);
wxDECLARE_EVENT(WX_POPUP_MENU_EVENT, PopupMenuEvent);

#ifdef _WIN32
class WinSendMessageEvent;
wxDECLARE_EVENT(WX_WIN_SEND_MESSAGE_EVENT, WinSendMessageEvent);
class WinSendMessageEvent: public wxCommandEvent
{
public:
        WinSendMessageEvent(void* hwnd, int message, INT_PARAM wParam, LONG_PARAM lParam) : wxCommandEvent(WX_WIN_SEND_MESSAGE_EVENT)
        {
                this->hwnd = hwnd;
                this->message = message;
                this->wParam = wParam;
                this->lParam = lParam;
        }
        WinSendMessageEvent(const WinSendMessageEvent& event) : wxCommandEvent(event)
        {
                this->hwnd = event.GetHWND();
                this->message = event.GetMessage();
                this->wParam = event.GetWParam();
                this->lParam = event.GetLParam();
        }

        wxEvent* Clone() const { return new WinSendMessageEvent(*this); }

        void* GetHWND() const { return hwnd; }
        int GetMessage() const { return message; }
        INT_PARAM GetWParam() const { return wParam; }
        LONG_PARAM GetLParam() const { return lParam; }

private:
        void* hwnd;
        int message;
        INT_PARAM wParam;
        LONG_PARAM lParam;
};
#endif

class CallbackEvent: public wxCommandEvent
{
public:
        CallbackEvent(WX_CALLBACK callback, void* data) : wxCommandEvent(WX_CALLBACK_EVENT)
        {
                this->callback = callback;
                this->data = data;
        }
        CallbackEvent(const CallbackEvent& event) : wxCommandEvent(event)
        {
                this->callback = event.GetCallback();
                this->data = event.GetData();
        }

        wxEvent* Clone() const { return new CallbackEvent(*this); }

        WX_CALLBACK GetCallback() const { return callback; }
        void* GetData() const { return data; }

private:
        WX_CALLBACK callback;
        void* data;


};

class PopupMenuEvent: public wxCommandEvent
{
public:
        PopupMenuEvent(wxWindow* window, wxMenu* menu, int* x, int* y) : wxCommandEvent(WX_POPUP_MENU_EVENT)
        {
                this->window = window;
                this->menu = menu;
                this->x = x;
                this->y = y;
        }
        PopupMenuEvent(const PopupMenuEvent& event) : wxCommandEvent(event)
        {
                this->window = event.GetWindow();
                this->menu = event.GetMenu();
                this->x = event.GetX();
                this->y = event.GetY();
        }

        wxEvent* Clone() const { return new PopupMenuEvent(*this); }

        wxWindow*  GetWindow() const { return window; }
        wxMenu* GetMenu() const { return menu; }
        int* GetX() const { return x; }
        int* GetY() const { return y; }

private:
        int* x;
        int* y;
        wxMenu* menu;
        wxWindow* window;
};

class Frame;

class App: public wxApp
{
public:
        App();
        virtual bool OnInit();
        virtual int OnRun();
        Frame* GetFrame()
        {
                return frame;
        }
private:
        Frame* frame;
};

class CExitThread: public wxThread
{
public:
	CExitThread(Frame* frame);
    virtual ~CExitThread() {}
private:
    wxThread::ExitCode Entry();
    Frame* frame;
};

class Frame: public wxFrame
{
public:
        Frame(App* app, const wxString& title, const wxPoint& pos,
                        const wxSize& size);

        virtual ~Frame() {}

        void Start();

        wxMenu* GetMenu();

private:
        void OnCommand(wxCommandEvent& event);
        void OnExitEvent(wxCommandEvent& event);
        void OnExitCompleteEvent(wxCommandEvent& event);
        void OnStopEmulationEvent(wxCommandEvent& event);
        void OnStopEmulationNowEvent(wxCommandEvent& event);
        void OnShowWindowEvent(wxCommandEvent& event);
        void OnPopupMenuEvent(PopupMenuEvent& event);
        void OnCallbackEvent(CallbackEvent& event);
        void OnClose(wxCloseEvent& event);
#ifdef _WIN32
        void OnWinSendMessageEvent(WinSendMessageEvent& event);
#endif

        void ShowConfigSelection();
        wxMenu* menu;

        bool closing;

        void Quit(bool stop_emulator = 1);

        wxDECLARE_EVENT_TABLE();
};

#endif /* SRC_WX_APP_H_ */
