/*******************************************************************************
* Copyright 2010-2020 Intel Corporation.
*
* This software and the related documents are Intel copyrighted  materials,  and
* your use of  them is  governed by the  express license  under which  they were
* provided to you (License).  Unless the License provides otherwise, you may not
* use, modify, copy, publish, distribute,  disclose or transmit this software or
* the related documents without Intel's prior written permission.
*
* This software and the related documents  are provided as  is,  with no express
* or implied  warranties,  other  than those  that are  expressly stated  in the
* License.
*******************************************************************************/

#ifndef __BASE_WINDOW_H__
#define __BASE_WINDOW_H__

#include "base_image.h"
#include "vm_thread.h"

#if defined ENABLE_RENDERING && defined _WIN32
#include <windows.h>

struct RendererContext
{
    RendererContext()
    {
        m_hWnd = NULL;
    }

    HWND m_hWnd;
};
#elif defined ENABLE_RENDERING && defined __unix__
#include <X11/Xlib.h>
#include <X11/Xutil.h>

struct RendererContext
{
    RendererContext()
    {
        m_pVisualInfo = NULL;
        m_pDisplay    = NULL;
        m_iScreen     = 0;
        m_window      = 0;
    }

    XVisualInfo* m_pVisualInfo;
    Display*     m_pDisplay;
    Window       m_window;
    unsigned int m_iScreen;
};
#else
#define KK_0 0
#define KK_1 0
#define KK_2 0
#define KK_3 0
#define KK_4 0
#define KK_5 0
#define KK_6 0
#define KK_7 0
#define KK_8 0
#define KK_9 0

#define KK_A 0
#define KK_B 0
#define KK_C 0
#define KK_D 0
#define KK_E 0
#define KK_F 0
#define KK_G 0
#define KK_H 0
#define KK_I 0
#define KK_J 0
#define KK_K 0
#define KK_L 0
#define KK_M 0
#define KK_N 0
#define KK_O 0
#define KK_P 0
#define KK_Q 0
#define KK_R 0
#define KK_S 0
#define KK_T 0
#define KK_U 0
#define KK_V 0
#define KK_W 0
#define KK_X 0
#define KK_Y 0
#define KK_Z 0

#define KK_ESCAPE 0
#define KK_SPACE  0
#define KK_ENTER  0
#define KK_LEFT   0
#define KK_RIGHT  0
#define KK_UP     0
#define KK_DOWN   0

struct RendererContext
{
    RendererContext()
    {
    }
};
#endif

enum KeyFlags
{
    KF_MESSAGE_UP   = 0x00000001,
    KF_STATE_CHANGE = 0x00000002,
    KF_EXT_KEY      = 0x00000004
};

typedef void (*KeyboardCallback)(int iKeyCode, int iCount, unsigned int iFlags, void *pParams);

struct WndFeedback
{
    WndFeedback()
    {
        iLastKey   = -1;
        iLastState = -1;

        keyCall         = NULL;
        keyCallParams   = NULL;

        bDestroyMessage = false;
        iRepaint        = 0;
    }

    volatile int iLastKey;
    int iLastState;

    KeyboardCallback  keyCall;
    void             *keyCallParams;

    volatile bool bDestroyMessage;
    volatile int iRepaint;
};

enum WindowStyle
{
    WSTYLE_NORMAL,
    WSTYLE_FIXED_SIZE,
    WSTYLE_BORDERLESS
};

struct WndRect
{
    int x;
    int y;
    unsigned int width;
    unsigned int height;
};

// base dummy class
class WindowBase
{
public:
    WindowBase()
    {
        m_wndRect.x     = m_wndRect.y      = 0;
        m_wndRect.width = m_wndRect.height = 0;
        m_iStyle        = WSTYLE_NORMAL;
        m_bFullscreen   = false;
        m_bWndCreated   = false;
    }

    virtual ~WindowBase()
    {
        WindowClose();
    }

    virtual bool WindowCreate(const char*, unsigned int = WSTYLE_NORMAL) { return false; };
    virtual void WindowSetRect(WndRect) { return; };
    virtual void WindowResize(unsigned int, unsigned int) { return; };
    virtual void WindowSetFullscreen(bool) { return; };
    virtual void WindowShow() { return; };
    virtual void WindowHide() { return; };
    virtual void WindowClose() { return; };
    virtual void WindowGetSize(unsigned int &, unsigned int &) { return; };
    virtual void GetWindowContext(RendererContext*) { return; };
    virtual void Invalidate() { return; };
    virtual void WaitMessages() { return; };
    virtual void CheckMessages() { return; };
    virtual Rect GetScreenRect(int) { return Rect(); };

    virtual void AddKeyboardCallback(KeyboardCallback fun, void *pParams)
    {
        m_feedback.keyCall       = fun;
        m_feedback.keyCallParams = pParams;
    };

    bool IsWindowExist() { return m_bWndCreated; };

    void WindowSwitchFullscreen()
    {
        WindowSetFullscreen(!m_bFullscreen);
    }

public:
    WndFeedback   m_feedback;

protected:
    WndRect       m_wndRect;
    unsigned int  m_iStyle;
    bool          m_bFullscreen;
    bool          m_bWndCreated;
};

#ifdef ENABLE_RENDERING
#if defined _WIN32
#define KK_0 0x30
#define KK_1 0x31
#define KK_2 0x32
#define KK_3 0x33
#define KK_4 0x34
#define KK_5 0x35
#define KK_6 0x36
#define KK_7 0x37
#define KK_8 0x38
#define KK_9 0x39

#define KK_A 0x41
#define KK_B 0x42
#define KK_C 0x43
#define KK_D 0x44
#define KK_E 0x45
#define KK_F 0x46
#define KK_G 0x47
#define KK_H 0x48
#define KK_I 0x49
#define KK_J 0x4A
#define KK_K 0x4B
#define KK_L 0x4C
#define KK_M 0x4D
#define KK_N 0x4E
#define KK_O 0x4F
#define KK_P 0x50
#define KK_Q 0x51
#define KK_R 0x52
#define KK_S 0x53
#define KK_T 0x54
#define KK_U 0x55
#define KK_V 0x56
#define KK_W 0x57
#define KK_X 0x58
#define KK_Y 0x59
#define KK_Z 0x5A

#define KK_ESCAPE VK_ESCAPE
#define KK_SPACE  VK_SPACE
#define KK_ENTER  VK_RETURN
#define KK_LEFT   VK_LEFT
#define KK_RIGHT  VK_RIGHT
#define KK_UP     VK_UP
#define KK_DOWN   VK_DOWN

class WindowWin : public WindowBase
{
public:
    WindowWin();
    virtual ~WindowWin();

    virtual bool WindowCreate(const char* cAppName, unsigned int iStyle = WSTYLE_NORMAL);
    virtual void WindowSetRect(WndRect wndRect);
    virtual void WindowResize(unsigned int iWidth, unsigned int iHeight);
    virtual void WindowSetFullscreen(bool bFullscreen);
    virtual void WindowShow();
    virtual void WindowHide();
    virtual void WindowClose();
    virtual void WindowGetSize(unsigned int &iWidth, unsigned int &iHeight);
    virtual void GetWindowContext(RendererContext *pContext);
    virtual void Invalidate();
    virtual void WaitMessages();
    virtual void CheckMessages();

protected:
    HWND   m_hWnd;
    ATOM   m_wndReg;
    MSG    m_message;
    HMENU *m_pMenu;
    LONG   m_WndStyle;
    LONG   m_WndStyleEx;
};
#elif defined __unix__
#include <X11/keysym.h>

#ifndef XK_0
#define KK_0 0x30
#define KK_1 0x31
#define KK_2 0x32
#define KK_3 0x33
#define KK_4 0x34
#define KK_5 0x35
#define KK_6 0x36
#define KK_7 0x37
#define KK_8 0x38
#define KK_9 0x39
#else
#define KK_0 XK_0
#define KK_1 XK_1
#define KK_2 XK_2
#define KK_3 XK_3
#define KK_4 XK_4
#define KK_5 XK_5
#define KK_6 XK_6
#define KK_7 XK_7
#define KK_8 XK_8
#define KK_9 XK_9
#endif

#ifndef XK_a
#define KK_A 0x61
#define KK_B 0x62
#define KK_C 0x63
#define KK_D 0x64
#define KK_E 0x65
#define KK_F 0x66
#define KK_G 0x67
#define KK_H 0x68
#define KK_I 0x69
#define KK_J 0x6A
#define KK_K 0x6B
#define KK_L 0x6C
#define KK_M 0x6D
#define KK_N 0x6E
#define KK_O 0x6F
#define KK_P 0x70
#define KK_Q 0x71
#define KK_R 0x72
#define KK_S 0x73
#define KK_T 0x74
#define KK_U 0x75
#define KK_V 0x76
#define KK_W 0x77
#define KK_X 0x78
#define KK_Y 0x79
#define KK_Z 0x7A
#else
#define KK_A XK_a
#define KK_B XK_b
#define KK_C XK_c
#define KK_D XK_d
#define KK_E XK_e
#define KK_F XK_f
#define KK_G XK_g
#define KK_H XK_h
#define KK_I XK_i
#define KK_J XK_j
#define KK_K XK_k
#define KK_L XK_l
#define KK_M XK_m
#define KK_N XK_n
#define KK_O XK_o
#define KK_P XK_p
#define KK_Q XK_q
#define KK_R XK_r
#define KK_S XK_s
#define KK_T XK_t
#define KK_U XK_u
#define KK_V XK_v
#define KK_W XK_w
#define KK_X XK_x
#define KK_Y XK_y
#define KK_Z XK_z
#endif

#define KK_ESCAPE XK_Escape
#define KK_SPACE  XK_space
#define KK_ENTER  XK_Return
#define KK_LEFT   XK_Left
#define KK_RIGHT  XK_Right
#define KK_UP     XK_Up
#define KK_DOWN   XK_Down

class WindowX : public WindowBase
{
public:
    WindowX();
    virtual ~WindowX();

    virtual bool WindowCreate(const char* cAppName, unsigned int iStyle = WSTYLE_NORMAL);
    virtual void WindowSetRect(WndRect wndRect);
    virtual void WindowResize(unsigned int iWidth, unsigned int iHeight);
    virtual void WindowSetFullscreen(bool bFullscreen);
    virtual void WindowShow();
    virtual void WindowHide();
    virtual void WindowClose();
    virtual void WindowGetSize(unsigned int &iWidth, unsigned int &iHeight);
    virtual void GetWindowContext(RendererContext *pContext);
    virtual void Invalidate();
    virtual void WaitMessages();
    virtual void CheckMessages();
    void WindowProc(XEvent &event);

protected:
    Display*     m_display;
    Window       m_window;
    XVisualInfo* m_pvisinfo;
    unsigned int m_iScreen;
    Atom         m_wmDelete;
    Time         m_iPrevPressTime;
};
#endif
#endif

#endif
