// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <memory>

#include "egl_stuff.h"
#include "main.h"
#include "xlib_window.h"

std::unique_ptr<GLInterface> g_main_gl_interface;

GLInterface* GLInterface::Create() {
  return new EGLInterface;
}

bool EGLInterface::Init() {
  if (!XlibInit())
    return false;

  EGLNativeWindowType native_window =
      static_cast<EGLNativeWindowType>(g_xlib_window);
  surface_ = eglCreateWindowSurface(display_, config_, native_window, NULL);
  CheckError();

  context_ = CreateContext();
  CheckError();

  eglMakeCurrent(display_, surface_, surface_, context_);
  CheckError();

  eglQuerySurface(display_, surface_, EGL_WIDTH, &g_width);
  eglQuerySurface(display_, surface_, EGL_HEIGHT, &g_height);

  return true;
}

void EGLInterface::Cleanup() {
  eglMakeCurrent(display_, NULL, NULL, NULL);
  DeleteContext(context_);
  eglDestroySurface(display_, surface_);
}

XVisualInfo* EGLInterface::GetXVisual() {
  if (!config_) {
    EGLint attribs[] = {
      EGL_RED_SIZE, 1,
      EGL_GREEN_SIZE, 1,
      EGL_BLUE_SIZE, 1,
      EGL_DEPTH_SIZE, 1,
      EGL_STENCIL_SIZE, 1,
      EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
      EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
      EGL_NONE
    };

    EGLNativeDisplayType native_display =
      static_cast<EGLNativeDisplayType>(g_xlib_display);

    display_ = eglGetDisplay(native_display);
    CheckError();

    eglInitialize(display_, NULL, NULL);
    CheckError();

    EGLint num_configs = -1;
    eglGetConfigs(display_, NULL, 0, &num_configs);
    CheckError();

    eglChooseConfig(display_, attribs, &config_, 1, &num_configs);
    CheckError();
  }

  // TODO: for some reason on some systems EGL_NATIVE_VISUAL_ID returns an ID
  // that XVisualIDFromVisual cannot find.  Use default visual until this is
  // resolved.
#if 0
  EGLint visual_id;
  eglGetConfigAttrib(display_, config_, EGL_NATIVE_VISUAL_ID, &visual_id);
  CheckError();
  XVisualInfo vinfo_template;
  vinfo_template.visualid = static_cast<VisualID>(visual_id);
#else
  XVisualInfo vinfo_template;
  vinfo_template.visualid = XVisualIDFromVisual(DefaultVisual(
      g_xlib_display, DefaultScreen(g_xlib_display)));
#endif

  int nitems = 0;
  XVisualInfo* ret = XGetVisualInfo(g_xlib_display, VisualIDMask,
                                    &vinfo_template, &nitems);
  CHECK(nitems == 1);
  return ret;
}

void EGLInterface::SwapBuffers() {
  eglSwapBuffers(display_, surface_);
}

bool EGLInterface::SwapInterval(int interval) {
  return (eglSwapInterval(display_, interval) == EGL_TRUE);
}

bool EGLInterface::MakeCurrent(const GLContext& context) {
  return eglMakeCurrent(display_, surface_, surface_, context);
}

const GLContext EGLInterface::CreateContext() {
  EGLint attribs[] = {
    EGL_CONTEXT_CLIENT_VERSION, 2,
    EGL_NONE
  };
  CHECK(display_ != EGL_NO_DISPLAY);
  CHECK(config_);
  return eglCreateContext(display_, config_, NULL, attribs);
}

void EGLInterface::CheckError() {
  CHECK_EQ(eglGetError(), EGL_SUCCESS);
}

void EGLInterface::DeleteContext(const GLContext& context) {
  eglDestroyContext(display_, context);
}

void EGLInterface::TerminateGL() {
  eglDestroySurface(display_, surface_);
  eglTerminate(display_);
}