/******************************************************************************
*	File		-	logGui.cpp
*	Author		-	Joey Pollack
*	Date		-	2021/09/09 (y/m/d)
*	Mod Date	-	2021/09/10 (y/m/d)
*	Description	-	A debug log window
******************************************************************************/

#include "logGui.h"
#include <core/core.h>
#include <window/window.h>
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
#include <sstream>

namespace lunarium
{
    ////////////////////////////////////////////////////////////
    //				GUI LOG LISTENER
    ////////////////////////////////////////////////////////////
    GuiListener::GuiListener(LogGui* pGui, uint32_t acceptedLogLevels, uint32_t acceptedLogCategories, const char* myName)
        : LogListener(acceptedLogLevels, acceptedLogCategories, myName), mpGui(pGui)
    {

    }

	bool GuiListener::Log(LogMessage& message)
    {
        if (!LevelIsSet(message.LogLevel) ||
			!CategoryIsSet(message.LogCategory))
			return false;

        std::ostringstream oss;

		oss << std::endl << Logger::TimeStamp() << Logger::GetCategoryName(message.LogCategory)
					<< Logger::GetLevelName(message.LogLevel) << message.Message << std::flush;
        
        mpGui->mMsgHistory.push_back(oss.str());
		return true;
    }

    ////////////////////////////////////////////////////////////
    //				GUI LOGGER
    ////////////////////////////////////////////////////////////
    LogGui* LogGui::mpInstance = nullptr;
    LogGui::LogGui()
        : mbShow(false), mListener(this), mbOglDebug(false), mbInfoVerbose(false)
    {

    }

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

        return *mpInstance;
    }

    void LogGui::FreeInstance()
    {
        Logger::GetInstance()->RemoveListener(&mpInstance->mListener);

        delete mpInstance;
        mpInstance = nullptr;
    }
    
    OpRes LogGui::Initialize()
    {
        Logger::GetInstance()->AddListener(&mListener);
        return OpRes::OK();
    }
    
    void LogGui::Show()
    {
        if (!mbShow)
            return;

        int x, y;
        Core::MainWindow().GetPosition(&x, &y);
        int width, height;
        Core::MainWindow().GetFramebufferSize(&width, &height);

        int logHeight = height / 2.0f;
        
        ImGui::SetNextWindowPos(ImVec2(x, y + logHeight), ImGuiCond_Always);
        ImGui::SetNextWindowSize(ImVec2((width / 3.0f) * 2.0f, logHeight), ImGuiCond_Always);
        if (!ImGui::Begin("Debug Log", &mbShow, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove
                                                  | ImGuiWindowFlags_NoSavedSettings))
        {
            ImGui::End();
            return;
        }
        ImGui::BeginChild("Message Types", ImVec2(0.0f, 20.0f));
        ImGui::Checkbox("OGL_DEBUG", &mbOglDebug);
        ImGui::SameLine();
        ImGui::Checkbox("INFO_VERBOSE", &mbInfoVerbose);
        ImGui::EndChild();
        ImGui::Separator();
        ImGui::BeginChild("scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar);
        ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
        for (int i = 0; i < mMsgHistory.size(); i++)
        {
            if ((mMsgHistory[i].find("[OGL_DEBUG]") != std::string::npos && !mbOglDebug)
            || (mMsgHistory[i].find("[INFO_VERBOSE]") != std::string::npos && !mbInfoVerbose))
            {
                continue;
            }

            ImVec4 color(1.0f, 1.0f, 1.0f, 1.0f);

            if (mMsgHistory[i].find("WANRING") != std::string::npos)
            {
                color = ImVec4(0.75f, 0.75f, 0.0f, 1.0f);
            }

            if (mMsgHistory[i].find("ERROR") != std::string::npos)
            {
                color = ImVec4(1.0f, 0.0f, 0.0f, 1.0f);
            }

            const char* msg = mMsgHistory[i].c_str();
            int len = strlen(msg);
            
            ImGui::PushTextWrapPos(ImGui::GetWindowWidth());
            ImGui::TextColored(color, msg);
            ImGui::PopTextWrapPos();
        }

        ImGui::PopStyleVar();
        if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
            ImGui::SetScrollHereY(1.0f);

        ImGui::EndChild();
        ImGui::End();
    }
    
    void LogGui::Clear()
    {
        mMsgHistory.clear();
    }
    
    void LogGui::SetShow(bool show)
    {
        mbShow = show;
    }
    
    bool LogGui::IsShown() const
    {
        return mbShow;
    }
}