#include "WaylandSurface.h"

#include "WaylandEglWindowInterface.h"

WaylandSurface::WaylandSurface(mt::Window* window)
    : mWindow(window)
{

}

WaylandSurface::~WaylandSurface()
{

}

void WaylandSurface::initialize(wl_compositor* compositor, xdg_wm_base* xdg_wm_base, std::shared_ptr<WaylandBuffer> buffer, WaylandEglInterface* eglInterface)
{
    mBuffer = buffer;
    if (eglInterface)
    {
        mEglWindowInterface = std::make_unique<WaylandEglWindowInterface>(eglInterface);
    }

    mSurface = wl_compositor_create_surface(compositor);
    mXdgSurface = xdg_wm_base_get_xdg_surface(xdg_wm_base, mSurface);

    auto xdg_surface_configure = [](void *data, struct xdg_surface *xdg_surface, uint32_t serial)
    {
        auto thisClass = static_cast<WaylandSurface*>(data);
        thisClass->onConfigure(xdg_surface, serial);
    };
    mXdgSurfaceListener.configure = xdg_surface_configure;

    xdg_surface_add_listener(mXdgSurface, &mXdgSurfaceListener, this);

    mXdgTopLevel = xdg_surface_get_toplevel(mXdgSurface);
    xdg_toplevel_set_title(mXdgTopLevel, "Example client");

    wl_surface_commit(mSurface);

    auto region = wl_compositor_create_region(compositor);
    wl_region_add(region, 0, 0, mWindow->GetWidth(), mWindow->GetHeight());
    wl_surface_set_opaque_region(mSurface, region);
}

void WaylandSurface::onConfigure(xdg_surface *xdg_surface, uint32_t serial)
{
    xdg_surface_ack_configure(xdg_surface, serial);

    if (mEglWindowInterface)
    {
        mEglWindowInterface->initialize(mSurface, mWindow->GetWidth(), mWindow->GetHeight());
        mEglWindowInterface->draw();
    }
    else
    {
        auto buffer = drawFrame();
        wl_surface_attach(mSurface, buffer, 0, 0);
        //wl_surface_damage(mSurface, 0, 0, UINT32_MAX, UINT32_MAX);
        wl_surface_commit(mSurface);
    }
}

wl_buffer* WaylandSurface::drawFrame()
{
    const auto width = mWindow->GetWidth();
    const auto height = mWindow->GetHeight();

    const int bitDepth = 4;

    const int stride = width * bitDepth;
    //const int numBuffers = 2; // i.e. front/back
    const int numBuffers = 1;
    const int shm_pool_size = height * stride * numBuffers;

    mBuffer->initializeSharedBuffer(shm_pool_size);
    mBuffer->setUpPool(shm_pool_size, width, height, stride);

    int offset = 0;
    drawCheckerboard(width, height, offset);

    mBuffer->tearDownPool(shm_pool_size);

    return mBuffer->getWorkingBuffer();
}

void WaylandSurface::drawCheckerboard(int width, int height, int offset)
{
    uint32_t *pixels = (uint32_t *)&(mBuffer->getPoolData())[offset];
    for (int y = 100; y < height; ++y)
    {
        for (int x = 0; x < width; ++x)
        {
            if ((x + y / 8 * 8) % 16 < 8)
            {
                pixels[y * width + x] = 0xFF666666;
            }
            else
            {
                pixels[y * width + x] = 0xFFEEEEEE;
            }
        }
    }
}

