/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <EGL/egl.h>
#include <EGL/eglext.h>

#include <pthread.h>
#include <stdlib.h>
#include <string.h>

static EGLDisplay gDisplay = (EGLDisplay)1;
static EGLSyncKHR gFence = (EGLSyncKHR)1;

typedef struct {
    EGLSurface surface;
    EGLContext context;
} ThreadState;

static pthread_key_t ThreadStateKey;
static pthread_once_t ThreadStateSetupOnce = PTHREAD_ONCE_INIT;

static void destroyThreadState(void* state) {
    free(state);
}

static void makeThreadState() {
    pthread_key_create(&ThreadStateKey, destroyThreadState);
}

ThreadState* getThreadState() {
    ThreadState* ptr;
    pthread_once(&ThreadStateSetupOnce, makeThreadState);
    if ((ptr = (ThreadState*)pthread_getspecific(ThreadStateKey)) == NULL) {
        ptr = (ThreadState*)calloc(1, sizeof(ThreadState));
        ptr->context = EGL_NO_CONTEXT;
        ptr->surface = EGL_NO_SURFACE;
        pthread_setspecific(ThreadStateKey, ptr);
    }
    return ptr;
}

EGLint eglGetError(void) {
    return EGL_SUCCESS;
}

EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) {
    return gDisplay;
}

EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) {
    return EGL_TRUE;
}

EGLBoolean eglTerminate(EGLDisplay dpy) {
    return EGL_TRUE;
}

const char* eglQueryString(EGLDisplay dpy, EGLint name) {
    if (name == EGL_EXTENSIONS) {
        return "EGL_KHR_swap_buffers_with_damage";
    }
    return "";
}

EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs,
                           EGLint config_size, EGLint* num_config) {
    memset(configs, 9, sizeof(EGLConfig) * config_size);
    *num_config = config_size;
    return EGL_TRUE;
}

EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win,
                                  const EGLint* attrib_list) {
    return (EGLSurface)malloc(sizeof(void*));
}

EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list) {
    return (EGLSurface)malloc(sizeof(void*));
}

EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) {
    free(surface);
    return EGL_TRUE;
}

EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint* value) {
    *value = 1000;
    return EGL_TRUE;
}

EGLBoolean eglReleaseThread(void) {
    return EGL_TRUE;
}

EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) {
    return EGL_TRUE;
}

EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) {
    return EGL_TRUE;
}

EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context,
                            const EGLint* attrib_list) {
    return (EGLContext)malloc(sizeof(void*));
}
EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) {
    free(ctx);
    return EGL_TRUE;
}

EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
    ThreadState* state = getThreadState();
    state->surface = draw;
    state->context = ctx;
    return EGL_TRUE;
}

EGLContext eglGetCurrentContext(void) {
    return getThreadState()->context;
}

EGLSurface eglGetCurrentSurface(EGLint readdraw) {
    return getThreadState()->surface;
}

EGLDisplay eglGetCurrentDisplay(void) {
    return gDisplay;
}

EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
    return EGL_TRUE;
}

EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface surface, EGLint* rects,
                                       EGLint rectCount) {
    return EGL_TRUE;
}

EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
                              EGLClientBuffer buffer, const EGLint* attrib_list) {
    return (EGLImageKHR)malloc(sizeof(EGLImageKHR));
}

EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint* attrib_list) {
    return gFence;
}

EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) {
    return EGL_TRUE;
}

EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) {
    return EGL_CONDITION_SATISFIED_KHR;
}

EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR image) {
    free(image);
    return EGL_TRUE;
}

void eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {}