#include "GlxInterface.h"

#include "OpenGlInterface.h"
#include "FileLogger.h"

#include <GL/gl.h>

GlxInterface::GlxInterface()
    : mContext(),
      mDrawable(),
      mWindow(),
      mConfig()
{

}

static int visual_attribs[] =
{
    GLX_X_RENDERABLE, True,
    GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
    GLX_RENDER_TYPE, GLX_RGBA_BIT,
    GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
    GLX_RED_SIZE, 8,
    GLX_GREEN_SIZE, 8,
    GLX_BLUE_SIZE, 8,
    GLX_ALPHA_SIZE, 8,
    GLX_DEPTH_SIZE, 24,
    GLX_STENCIL_SIZE, 8,
    GLX_DOUBLEBUFFER, True,
    //GLX_SAMPLE_BUFFERS  , 1,
    //GLX_SAMPLES         , 4,
    None
};

std::unique_ptr<GlxInterface> GlxInterface::Create()
{
    return std::make_unique<GlxInterface>();
}

void GlxInterface::SetupContext(Display* display, int default_screen)
{
    /* Query framebuffer configurations that match visual_attribs */
    int num_fb_configs = 0;
    GLXFBConfig* fb_configs = glXChooseFBConfig(display, default_screen, visual_attribs, &num_fb_configs);
    if (!fb_configs || num_fb_configs == 0)
    {
        MLOG_ERROR("glXGetFBConfigs failed");
        return;
    }

    /* Select first framebuffer config and query visualID */
    int visualID = 0;
    mConfig = fb_configs[0];
    glXGetFBConfigAttrib(display, mConfig, GLX_VISUAL_ID, &visualID);

    /* Create OpenGL context */
    mContext = glXCreateNewContext(display, mConfig, GLX_RGBA_TYPE, 0, True);
    if (!mContext)
    {
        MLOG_ERROR("glXCreateNewContext failed");
        return;
    }
}

void GlxInterface::SwapBuffers(Display* display)
{
    glXSwapBuffers(display, mDrawable);
}

void GlxInterface::Draw()
{
    OpenGlInterface::draw();
}

bool GlxInterface::SetupWindow(Display* display, xcb_window_t window)
{
    /* Create GLX Window */
    mWindow = glXCreateWindow(display, mConfig, window, 0);
    if (!mWindow)
    {
        glXDestroyContext(display, mContext);
        MLOG_ERROR("glXCreateWindow failed");
        return false;
    }

    mDrawable = mWindow;

    /* make OpenGL context current */
    if (!glXMakeContextCurrent(display, mDrawable, mDrawable, mContext))
    {
        glXDestroyContext(display, mContext);
        MLOG_ERROR("glXMakeContextCurrent failed");
        return false;
    }
    return true;
}

void GlxInterface::DestroyWindow(Display* display)
{
    glXDestroyWindow(display, mWindow);
}

void GlxInterface::DestroyContext(Display* display)
{
    glXDestroyContext(display, mContext);
}
