#include "WaylandBuffer.h"

#include "FileLogger.h"

#include <sys/mman.h>
#include <unistd.h>

void WaylandBuffer::initializeSharedBuffer(int size)
{
    mSharedMemory = std::make_unique<SharedMemory>();
    mSharedMemory->allocate("/wl_shm-XXXXXX", size);

    if (!mSharedMemory->isValid())
    {
        return;
    }

    mPoolData = static_cast<uint8_t*>(mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, mSharedMemory->getFileDescriptor(), 0));
    if (mPoolData == MAP_FAILED)
    {
        close(mSharedMemory->getFileDescriptor());
        mPoolData = nullptr;
    }
}

void WaylandBuffer::setSharedMemory(wl_shm* shared_memory)
{
    mWlSharedMemory = shared_memory;
}

void WaylandBuffer::setUpPool(int size, int width, int height, int stride)
{
    if (!mSharedMemory->isValid())
    {
        MLOG_ERROR("Failed to allocate shared memory.");
        return;
    }

    if (!mPoolData)
    {
        MLOG_ERROR("Failed to allocate shared memory.");
        return;
    }

    auto pool = wl_shm_create_pool(mWlSharedMemory, mSharedMemory->getFileDescriptor(), size);

    int index = 0;
    // int offset = height * stride * index; // Two buffers, offset to starting point of second
    int offset = 0;

    mWorkingBuffer = wl_shm_pool_create_buffer(pool, offset, width, height, stride, WL_SHM_FORMAT_XRGB8888);

    wl_shm_pool_destroy(pool);
    close(mSharedMemory->getFileDescriptor());
}

void WaylandBuffer::tearDownPool(int size)
{
    munmap(mPoolData, size);

    auto wl_buffer_release = [](void *data, struct wl_buffer *wl_buffer)
    {
        wl_buffer_destroy(wl_buffer);
    };
    mBufferListener.release = wl_buffer_release;

    wl_buffer_add_listener(mWorkingBuffer, &mBufferListener, nullptr);
}

uint8_t* WaylandBuffer::getPoolData()
{
    return mPoolData;
}

wl_buffer* WaylandBuffer::getWorkingBuffer()
{
    return mWorkingBuffer;
}
