#include "xwlutils.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

using namespace std;

static xcb_atom_t primaryAtom = XCB_ATOM_NONE;
static xcb_atom_t clipboardAtom = XCB_ATOM_NONE;
static xcb_atom_t utf8StringAtom = XCB_ATOM_NONE;
static xcb_atom_t textAtom = XCB_ATOM_NONE;
static xcb_atom_t uriListAtom = XCB_ATOM_NONE;
static xcb_atom_t targetsAtom = XCB_ATOM_NONE;
static xcb_atom_t wlSelectionAtom = XCB_ATOM_NONE;
static xcb_atom_t timestampAtom = XCB_ATOM_NONE;
static xcb_atom_t incrAtom = XCB_ATOM_NONE;
static xcb_atom_t deleteAtom = XCB_ATOM_NONE;

xcb_atom_t XwlUtils::getAtom(const char *str, xcb_connection_t *xcbConn)
{
    xcb_atom_t atom = XCB_ATOM_NONE;
    if (!strcmp(str, "PRIMARY") && primaryAtom != XCB_ATOM_NONE) {
        return primaryAtom;
    } else if (!strcmp(str, "CLIPBOARD") && clipboardAtom != XCB_ATOM_NONE) {
        return clipboardAtom;
    } else if (!strcmp(str, "UTF8_STRING") && utf8StringAtom != XCB_ATOM_NONE) {
        return utf8StringAtom;
    } else if (!strcmp(str, "TEXT") && textAtom != XCB_ATOM_NONE) {
        return textAtom;
    } else if (!strcmp(str, "text/uri-list") && uriListAtom != XCB_ATOM_NONE) {
        return uriListAtom;
    } else if (!strcmp(str, "TARGETS") && targetsAtom != XCB_ATOM_NONE) {
        return targetsAtom;
    } else if (!strcmp(str, "WL_SELECTION") && wlSelectionAtom != XCB_ATOM_NONE) {
        return wlSelectionAtom;
    } else if (!strcmp(str, "TIMESTAMP") && timestampAtom != XCB_ATOM_NONE) {
        return timestampAtom;
    } else if (!strcmp(str, "INCR") && incrAtom != XCB_ATOM_NONE) {
        return incrAtom;
    } else if (!strcmp(str, "DELETE") && deleteAtom != XCB_ATOM_NONE) {
        return deleteAtom;
    }

    if (xcbConn) {
        xcb_intern_atom_reply_t *rep = nullptr;
        uint16_t name_len = strlen(str);
        xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xcbConn, 0, strlen(str), str);
        if (!(rep = xcb_intern_atom_reply(xcbConn, cookie, NULL))) {
            return atom;
        }
        atom = rep->atom;
        free(rep);
    }
    // 记录atom
    if (!strcmp(str, "PRIMARY")) {
        primaryAtom = atom;
    } else if (!strcmp(str, "CLIPBOARD")) {
        clipboardAtom = atom;
    } else if (!strcmp(str, "UTF8_STRING")) {
        utf8StringAtom = atom;
    } else if (!strcmp(str, "TEXT")) {
        textAtom = atom;
    } else if (!strcmp(str, "text/uri-list")) {
        uriListAtom = atom;
    } else if (!strcmp(str, "TARGETS")) {
        targetsAtom = atom;
    } else if (!strcmp(str, "WL_SELECTION")) {
        wlSelectionAtom = atom;
    } else if (!strcmp(str, "TIMESTAMP")) {
        timestampAtom = atom;
    } else if (!strcmp(str, "INCR")) {
        incrAtom = atom;
    } else if (!strcmp(str, "DELETE")) {
        deleteAtom = atom;
    }

    return atom;
}

string XwlUtils::atomName(xcb_atom_t atom, xcb_connection_t *xcbConn)
{
    xcb_get_atom_name_cookie_t nameCookie = xcb_get_atom_name(xcbConn, atom);
    xcb_get_atom_name_reply_t *nameReply = xcb_get_atom_name_reply(xcbConn, nameCookie, nullptr);
    if (!nameReply) {
        return string();
    }

    const size_t length = xcb_get_atom_name_name_length(nameReply);
    string name(xcb_get_atom_name_name(nameReply), length);
    free(nameReply);
    return name;
}

xcb_atom_t XwlUtils::mimeTypeToAtom(const string &mimeType, xcb_connection_t *xcbConn)
{
    if (!strcmp(mimeType.c_str(), "text/plain;charset=utf-8")) {
        return getAtom("UTF8_STRING", xcbConn);
    }
    if (!strcmp(mimeType.c_str(), "text/plain")) {
        return getAtom("TEXT", xcbConn);
    }
    if (!strcmp(mimeType.c_str(), "text/x-uri")) {
        return getAtom("text/uri-list", xcbConn);
    }
    return mimeTypeToAtomLiteral(mimeType, xcbConn);
}

xcb_atom_t XwlUtils::mimeTypeToAtomLiteral(const string &mimeType, xcb_connection_t *xcbConn)
{
    return getAtom(mimeType.c_str(), xcbConn);
}

vector<string> XwlUtils::atomToMimeTypes(xcb_atom_t atom, xcb_connection_t *xcbConn)
{
    vector<string> mimeTypes;
    if (atom == getAtom("UTF8_STRING", xcbConn)) {
        mimeTypes.push_back("text/plain;charset=utf-8");
    } else if (atom == getAtom("TEXT", xcbConn)) {
        mimeTypes.push_back("text/plain");
    } else if (atom == getAtom("text/uri-list", xcbConn)) {
        mimeTypes.push_back("text/uri-list");
        mimeTypes.push_back("text/x-uri");
    } else {
        mimeTypes.push_back(atomName(atom, xcbConn));
    }
    return mimeTypes;
}

xcb_window_t XwlUtils::getSelectionOwner(xcb_connection_t *xcbConn)
{
    xcb_window_t result = 0;
    xcb_get_selection_owner_cookie_t cookie =
        xcb_get_selection_owner(xcbConn, getAtom("CLIPBOARD", xcbConn));

    xcb_get_selection_owner_reply_t *reply =
        xcb_get_selection_owner_reply(xcbConn, cookie, nullptr);
    if (reply) {
        result = reply->owner;
        free(reply);
    }
    return result;
}
