/******************************************************************************
*	File		-	gui.cpp
*	Author		-	Joey Pollack
*	Date		-	2021/09/09 (y/m/d)
*	Mod Date	-	2021/09/09 (y/m/d)
*	Description	-	The main class that manages Dear ImGui
******************************************************************************/

#include "gui.h"

#include <window/window.h>
#include <utils/helpers.h>
#include <utils/logger.h>
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>

namespace lunarium
{
    GUI* GUI::mpInstance = nullptr;
    GUI::GUI()
        : mbIsInit(false), mbShowDemo(false)
    {

    }

    GUI& GUI::GetInstance()
    {
        if (!mpInstance)
        {
            mpInstance = new GUI;
        }

        return *mpInstance;
    }

    void GUI::FreeInstance()
    {
        delete mpInstance;
        mpInstance = nullptr;
    }

    OpRes GUI::Initialize(Window* pWindow)
    {
        if (mbIsInit)
        {
            return OpRes::Fail("GUI is already initialized!");
        }

        IMGUI_CHECKVERSION();
        ImGui::CreateContext();
        ImGuiIO& io = ImGui::GetIO(); (void)io;
        io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;       // Enable Keyboard Controls
        //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls
        io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;           // Enable Docking
        io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;         // Enable Multi-Viewport / Platform Windows

        // Setup Dear ImGui style
        ImGui::StyleColorsDark();

        // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
        ImGuiStyle& style = ImGui::GetStyle();
        if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
        {
            style.WindowRounding = 0.0f;
            style.Colors[ImGuiCol_WindowBg].w = 1.0f;
        }

        // Setup Platform/Renderer backends
        ImGui_ImplGlfw_InitForOpenGL(pWindow->GetWindow(), true);
        ImGui_ImplOpenGL3_Init(System::GetGLSLVersionString().c_str());

        // Our state
        ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
        mbShowDemo = true;

        Logger::Log(LogCategory::GRAPHICS, LogLevel::INFO, "ImGui setup");
        mbIsInit = true;
        return OpRes::OK();
    }

    void GUI::Shutdown()
    {
        ImGui_ImplOpenGL3_Shutdown();
        ImGui_ImplGlfw_Shutdown();
        ImGui::DestroyContext();

        mbIsInit = false;
    }

    bool GUI::WantCaptureKeyboard() const
    {
        return ImGui::GetIO().WantCaptureKeyboard;
    }

    void GUI::NewFrame()
    {
        if (!mbIsInit)
            return;

        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();
        ImGui::NewFrame();
    }

    void GUI::EndFrame()
    {
        ImGui::Render();
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
        {
            GLFWwindow* backup_current_context = glfwGetCurrentContext();
            ImGui::UpdatePlatformWindows();
            ImGui::RenderPlatformWindowsDefault();
            glfwMakeContextCurrent(backup_current_context);
        }
    }

    void GUI::ShowDemoWindow()
    {
        if (!mbIsInit)
            return;
            
        ImGui::ShowDemoWindow(&mbShowDemo);       
    }
}