#include "ukuidisplay_p.h"

#include <QDebug>

#include <QGuiApplication>

#include <QtGui/qpa/qplatformnativeinterface.h>

static UkuiDisplay *s_ukuiDisplay = nullptr;
UkuiDisplay *ukuiDisplay()
{
    if (!s_ukuiDisplay) {
        s_ukuiDisplay = new UkuiDisplay();
    }

    return s_ukuiDisplay;
}

UkuiDisplay::UkuiDisplay(QObject *parent)
    : QObject(parent)
{
    m_initialized = init();
}

UkuiDisplay::~UkuiDisplay()
{
}

bool UkuiDisplay::init()
{
    if (QGuiApplication::platformName() != "wayland") {
        return false;
    }

    QPlatformNativeInterface *native = qApp->platformNativeInterface();
    if (!native) {
        qWarning() << "Failed to get QPlatformNativeInterface";
        return false;
    }

    auto display = static_cast<wl_display *>(native->nativeResourceForIntegration("wl_display"));
    if (!display) {
        qWarning() << "Failed to get native display";
        return false;
    }

    m_display = std::make_unique<wayland::display_t>(display);
    if (!m_display) {
        qWarning() << "Failed to get wl_display";
        return false;
    }

    m_seat = wayland::seat_t(static_cast<wl_seat *>(native->nativeResourceForIntegration("wl_seat")), wayland::proxy_t::wrapper_type::foreign);
    if (!m_seat) {
        qWarning() << "Failed to get wl_seat";
        return false;
    }

    m_registry = m_display->get_registry();
    if (!m_registry) {
        qWarning() << "Failed to get wl_registry";
        return false;
    }

    m_registry.on_global() = std::bind(&UkuiDisplay::handle_global, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
    m_registry.on_global_remove() = std::bind(&UkuiDisplay::handle_global_remove, this, std::placeholders::_1);

    // roundtrip to get all global interfaces
    m_display->roundtrip();

    return true;
}

bool UkuiDisplay::isInitialized() const
{
    return m_initialized;
}

const wayland::display_t &UkuiDisplay::display() const
{
    return *m_display;
}

const wayland::seat_t &UkuiDisplay::seat() const
{
    return m_seat;
}

void UkuiDisplay::handle_global(uint32_t name, const std::string &interface, uint32_t version)
{
    m_globalInterfaces.append({name, interface, version});
}

void UkuiDisplay::handle_global_remove(uint32_t name)
{
    for (int i = 0; i < m_globalInterfaces.size(); ++i) {
        if (m_globalInterfaces.at(i).name == name) {
            m_globalInterfaces.removeAt(i);
            break;
        }
    }
}

QList<UkuiDisplay::WaylandInterface> UkuiDisplay::globalInterfaces()
{
    return m_globalInterfaces;
}

wayland::proxy_t UkuiDisplay::bind(const std::string &name, wayland::proxy_t &proxy, uint32_t minVersion)
{
    if (QGuiApplication::platformName() != "wayland") {
        return nullptr;
    }

    if (!isInitialized()) {
        return nullptr;
    }

    for (const WaylandInterface &interface : m_globalInterfaces) {
        if (interface.interface == name) {
            return m_registry.bind(interface.name, proxy, qMax(interface.version, minVersion));
        }
    }
    return nullptr;
}
