/*
 * Copyright (C) 2020 Uniontech Technology Co., Ltd.
 *
 * Author:     xinbo wang <wangxinbo@uniontech.com>
 *
 * Maintainer: xinbo wang <wangxinbo@uniontech.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "wayland_client_management.h"

#include "dtk_wmjack_wayland.h"

#include "log.h"

#include "glad/glad.h"
#include "EGL/egl.h"

int wInitWmJack()
{
    if (!pWmJack) {
        log_error("need init dtkdisplay content");
        return -1;
    }

    WaylandClientBackendPtr pWayland = (WaylandClientBackendPtr)malloc(sizeof(WaylandClientBackend));
    memset(pWayland, 0, sizeof(WaylandClientBackend));
    if (!pWayland) {
        fprintf(stderr, "malloc wayland backend failed \n");
        return -1;
    }

    pWmJack->backend = pWayland;

    return init_wayland_client();
}

void wDestoryWmJack()
{
    if (!pWmJack->backend) {
        log_error("wayland backend has been destroyed \n");
        return;
    }

    destory_wayland_client();
}

int wMaximizeWindow(WindowId wid)
{
    return -1;
}

int wMinimizeWindow(WindowId wid)
{
    return -1;
}

int wRestoreWindow(WindowId wid)
{
    return -1;
}

char *wGetWindowText(WindowId wid)
{
    return get_client_window_title(wid);
}

Size wGetWindowSize(WindowId wid)
{
    return get_client_window_size(wid);
}

Position wGetWindowPosition(WindowId wid)
{
    return get_client_window_position(wid);
}

WindowId wGetActiveWindowID()
{
    return 0;
}

WindowId wGetDesktopWindowID()
{
    return 0;
}

int wGetWindowChildren(WindowId wid, WindowId **pChildIDs)
{
    return -1;
}

Position wGetPointerPosition()
{
    Position position;
    position.x = -1;
    position.y = -1;

    return position;
}

void wFreeWindowList(WindowId *windownlist) {}

struct dtk_array *wGetAllWindowStates()
{
    return get_client_all_window_states();
}

WindowState *wGetWindowState(WindowId wid)
{
    return get_client_window_state(wid);
}

int wGetWindowPID(WindowId wid)
{
    return get_client_window_pid(wid);
}

WindowId wGetWindowFromPoint()
{
    return get_window_from_point();
}

void wShowSplitMenu(int x, int y, int width, int height, WindowId wid)
{
    show_split_menu(x, y, width, height, wid);
}

void wHideSplitMenu(bool delay, WindowId wid)
{
    hide_split_menu(delay);
}

char *wGetRendererString()
{
    static int windowWidth = 256, windowHeight = 256;
    static EGLint egl_config_attribs[] = {
        EGL_RED_SIZE,
        8,
        EGL_GREEN_SIZE,
        8,
        EGL_BLUE_SIZE,
        8,
        EGL_DEPTH_SIZE,
        8,
        EGL_SURFACE_TYPE,
        EGL_PBUFFER_BIT,
        EGL_RENDERABLE_TYPE,
        EGL_OPENGL_BIT,
        EGL_NONE
    };
    EGLint egl_pbuffer_attribs[] = {
        EGL_WIDTH, windowWidth, EGL_HEIGHT, windowHeight,
        EGL_NONE,
    };

    EGLDisplay egl_display = eglGetDisplay(NULL);
    if (!eglInitialize(egl_display, NULL, NULL)) {
        fprintf(stderr, "eglInitialize error\n");
        return NULL;
    }

    if (!eglBindAPI(EGL_OPENGL_API)) {
        fprintf(stderr, "eglBindAPI error\n");
        return NULL;
    }

    EGLConfig egl_config;
    EGLint num_configs;
    if (!eglChooseConfig(egl_display, egl_config_attribs, &egl_config, 1, &num_configs)) {
        fprintf(stderr, "eglChooseConfig error\n");
        return NULL;
    }
    if (num_configs != 1) {
        fprintf(stderr, "no enough config\n");
        return NULL;
    }

    EGLSurface egl_surface = eglCreatePbufferSurface(egl_display, egl_config, egl_pbuffer_attribs);
    if (egl_surface == EGL_NO_SURFACE) {
        fprintf(stderr, "create surface error\n");
        return NULL;
    }

    EGLContext egl_context = eglCreateContext(egl_display, egl_config, EGL_NO_CONTEXT, NULL);
    if (!egl_context) {
        fprintf(stderr, "create context error\n");
        return NULL;
    }

    if (!eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context)) {
        fprintf(stderr, "make current context error\n");
        return NULL;
    }

    if (!gladLoadGLLoader(eglGetProcAddress)) {
        fprintf(stderr, "gladLoadGLLoader error\n");
        return NULL;
    }

    char *result = NULL;
    const char *render = glGetString(GL_RENDERER);
    if (render) {
        const int length = strlen(render);
        if (length != 0) {
            result = (char *)malloc(length + 1);
            strcpy(result, render);
            for (char *p = result; *p; ++p) {
                if (isalpha(*p))
                    *p = tolower(*p);
            }
        }
    }

    return result;
}

WindowState wGetSpecificWindowState(uint32_t wid)
{
    return get_specific_window_state(wid);
}

int wGetAllWindowStatesList(WindowState **states)
{
    return get_all_window_states_list(states);
}