#pragma once

#include "AbstractUiInterface.h"

#include <memory>

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;

namespace mt
{
    class Window;
}

class XcbInterface : public AbstractUIInterface
{
public:
    XcbInterface(DesktopManager* desktopManager);

    ~XcbInterface();

    void initialize() override;

    void loop() override;

    void shutDown() override;

    void showWindow(mt::Window* window) override;

    void addWindow(mt::Window* window) override;

private:
    void onPaint();
    void onEventsDispatched();
    void onLoopCompleted();
    void onExposeEvent(xcb_expose_event_t* event);

    void initializeOpenGl();
    void createGraphicsContext();
    void createOpenGlDrawable(mt::Window* window);

    void connect();
    void updateScreen();
    void mapWindow(mt::Window* window);

    uint32_t getEventMask();

private:
    DesktopManager* mDesktopManager{nullptr};
    xcb_connection_t* mConnection;
    _XDisplay* mX11Display;
    GlxInterfacePtr mGlxInterface;
    XcbEventInterfacePtr mXcbEventInterface {nullptr};
    XcbWindowInterfacePtr mXcbWindowInterface {nullptr};
};
