#pragma once

#include "AbstractUiInterface.h"

#include <memory>

class XcbGlInterface;
using XcbGlInterfacePtr = std::unique_ptr<XcbGlInterface>;

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

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

class XcbExtensionInterface;

struct xcb_connection_t;
struct xcb_expose_event_t;
struct _XDisplay;

namespace mt
{
    class Window;
}

class XcbInterface : public AbstractUIInterface
{
public:
    XcbInterface(DesktopManager* desktopManager, bool useHardware = true);

    ~XcbInterface();

    void loop() override;

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

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

private:
    void createGraphicsContext();

    void connect();

    uint32_t getEventMask();

    void initialize() override;
    void initializeHardwareRendering() override;

    void onPaint();
    void onExposeEvent(xcb_expose_event_t* event);

    void mapWindow(mt::Window* window);

    void shutDown() override;

    void updateScreen();
private:
    xcb_connection_t* mConnection{nullptr};
    _XDisplay* mX11Display{nullptr};
    XcbGlInterfacePtr mGlInterface;
    XcbEventInterfacePtr mEventInterface;
    std::unique_ptr<XcbExtensionInterface> mExtensionInterface;
};
