#pragma once

#include <xcb/xcb.h>

#include <vector>

struct xcb_xfixes_selection_notify_event_t;

class X11Source;
class ClipData;

class XwlSelection
{
public:
    XwlSelection(xcb_atom_t atom, xcb_window_t parent, const xcb_query_extension_reply_t *queryExtension, xcb_connection_t *xcbConn);
    virtual ~XwlSelection();

    xcb_atom_t atom() const
    {
        return m_atom;
    }
    xcb_window_t window() const
    {
        return m_window;
    }
    xcb_window_t requestorWindow() const
    {
        return m_requestorWindow;
    }
    xcb_window_t parentWindow() const
    {
        return m_parentWindow;
    }
    xcb_connection_t *x11Connection() const
    {
        return m_xcbConn;
    }
    xcb_atom_t targetsAtom() const
    {
        return m_targetsAtom;
    }
    xcb_atom_t wlSelectionAtom() const
    {
        return m_wlSelectionAtom;
    }
    xcb_atom_t timestampAtom() const
    {
        return m_timestampAtom;
    }
    xcb_atom_t deleteAtom() const
    {
        return m_deleteAtom;
    }
    void ownSelection(bool own);
    void sendSelectionNotify(xcb_selection_request_event_t *event, bool success);

    static xcb_atom_t getAtom(const char *str);
    bool handleXfixesNotify(xcb_xfixes_selection_notify_event_t *event);
    bool filterEvent(xcb_generic_event_t *event);

    void clearEndPropertys();
    void timeout();

protected:
    virtual void doHandleXfixesNotify(xcb_xfixes_selection_notify_event_t *event) = 0;
    virtual bool handleSelectionNotify(xcb_selection_notify_event_t *event);

    virtual bool handleClientMessage(xcb_client_message_event_t *event)
    {
        return false;
    }

    bool createX11Source(xcb_xfixes_selection_notify_event_t *event = nullptr);
    void deleteX11Source();
    X11Source *x11Source() const
    {
        return m_x11Source;
    }

private:
    bool handleSelectionRequest(xcb_selection_request_event_t *event);
    bool handlePropertyNotify(xcb_property_notify_event_t *event);

private:
    xcb_connection_t *m_xcbConn = nullptr;
    const xcb_query_extension_reply_t *m_queryExtension = nullptr;
    xcb_atom_t m_atom = XCB_ATOM_NONE;
    xcb_window_t m_window = XCB_WINDOW_NONE;
    xcb_window_t m_requestorWindow = XCB_WINDOW_NONE;
    xcb_window_t m_parentWindow = XCB_WINDOW_NONE;
    xcb_timestamp_t m_timestamp;
    xcb_atom_t m_targetsAtom = XCB_ATOM_NONE;
    xcb_atom_t m_wlSelectionAtom = XCB_ATOM_NONE;
    xcb_atom_t m_timestampAtom = XCB_ATOM_NONE;
    xcb_atom_t m_deleteAtom = XCB_ATOM_NONE;

    // Active source, if any. Only one of them at max can exist
    // at the same time.
    X11Source *m_x11Source = nullptr;

    bool m_disownPending = false;
};
