#define _GNU_SOURCE 1
#include "FbCapture.h"

#include <tuple>
#include <dlfcn.h>
#include <QtGlobal>

namespace {
uchar *g_bits = nullptr;
int g_w = 0, g_h = 0, g_bpl = 0, g_fmt = 0;
}

// Interposes EPFramebuffer::setBuffers(std::tuple<QImage,QImage>, QImage*).
// The tuple is non-trivially-copyable, so passed by reference (a pointer); the
// QImage* is a pointer. We capture buffer A's pixel pointer/geometry, then chain
// to the real implementation.
extern "C" void _ZN13EPFramebuffer10setBuffersESt5tupleIJ6QImageS1_EEPS1_(
    void *self, void *tuplePtr, void *imgPtr)
{
    static void (*real)(void *, void *, void *) = nullptr;
    if (!real)
        real = (void (*)(void *, void *, void *))dlsym(
            RTLD_NEXT, "_ZN13EPFramebuffer10setBuffersESt5tupleIJ6QImageS1_EEPS1_");

    auto *t = reinterpret_cast<std::tuple<QImage, QImage> *>(tuplePtr);
    const QImage &a = std::get<0>(*t);
    g_bits = const_cast<uchar *>(a.constBits());
    g_w = a.width();
    g_h = a.height();
    g_bpl = a.bytesPerLine();
    g_fmt = int(a.format());
    qInfo("FbCapture: framebuffer %dx%d fmt=%d bpl=%d bits=%p",
          g_w, g_h, g_fmt, g_bpl, (void *)g_bits);

    if (real) real(self, tuplePtr, imgPtr);
}

namespace FbCapture {

bool ready() { return g_bits != nullptr; }

QImage framebuffer()
{
    if (!g_bits)
        return QImage();
    return QImage(g_bits, g_w, g_h, g_bpl, QImage::Format(g_fmt));
}

} // namespace FbCapture
