#pragma once

#include "Window.h"

#include <memory>
#include <map>

class DesktopManager;
class GlxInterface;
using GlxInterfacePtr = std::unique_ptr<GlxInterface>;

class XcbEventInterface;
using XcbEventInterfacePtr = std::unique_ptr<XcbEventInterface>;

class XcbWindowInterface;
using XcbWindowInterfacePtr = std::unique_ptr<XcbWindowInterface>;

struct xcb_connection_t;
struct xcb_expose_event_t;
struct _XDisplay;

class XcbInterface
{
public:
    XcbInterface();

    ~XcbInterface();

    void SetUseOpenGl(bool use);

    void Initialize(DesktopManager* desktopManager);

    void Loop(DesktopManager* desktopManager);

    void ShutDown();

    void ShowWindow(mt::Window* window);

    void AddWindow(mt::Window* window, DesktopManager* desktopManager);

    void CreateOpenGlDrawable(mt::Window* window);

private:
    void onPaint(DesktopManager* desktopManager);

    void InitializeOpenGl();

    void Connect();

    void UpdateScreen(DesktopManager* desktopManager);

    void OnExposeEvent(xcb_expose_event_t* event, DesktopManager* desktopManager);

    uint32_t GetEventMask();

    void MapWindow(mt::Window* window);

    void CreateGraphicsContext(DesktopManager* desktopManager);

    void onEventsDispatched(DesktopManager* desktopManager);
    void OnLoopCompleted(DesktopManager* desktopManagers);

private:
    bool mUseOpenGl {false};
    xcb_connection_t* mConnection;
    _XDisplay* mX11Display;
    GlxInterfacePtr mGlxInterface;
    XcbEventInterfacePtr mXcbEventInterface {nullptr};
    XcbWindowInterfacePtr mXcbWindowInterface {nullptr};
};
