/******************************************************************************
*	File		-	luaConsole.cpp
*	Author		-	Joey Pollack
*	Date		-	2021/09/17 (y/m/d)
*	Mod Date	-	2021/09/17 (y/m/d)
*	Description	-	GUI window for the LUA console
******************************************************************************/

#include "luaConsole.h"
#include <core/core.h>
#include <input/input_manager.h>
#include <window/window.h>
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
#include <cstring>

namespace lunarium
{
    LuaConsole* LuaConsole::mpInstance = nullptr;
    LuaConsole::LuaConsole()
        : mbShow(false), mbStickToWindow(true), mbNewCommand(false), mRecalledCommand(-1)
    {
        memset(mBuffer, 0, LUA_CON_BUFFER_SIZE);
    }
    
    LuaConsole& LuaConsole::GetInstance()
    {
        if (!mpInstance)
        {
            mpInstance = new LuaConsole;
        }

        return *mpInstance;
    }
    
    void LuaConsole::FreeInstance()
    {
        delete mpInstance;
        mpInstance = nullptr;
    }
    
    OpRes LuaConsole::Initialize()
    {
        return OpRes::OK();
    }

    int LuaConsole::MyCallback(ImGuiInputTextCallbackData* data)
    {
        if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
        {
            bool changeCommand = false;
            if (data->EventKey == ImGuiKey_UpArrow)
            {
                mpInstance->mRecalledCommand--;
                if (mpInstance->mRecalledCommand <= -1)
                {
                    mpInstance->mRecalledCommand = mpInstance->mCommandHistory.size() - 1;
                }
                changeCommand = true;
            }
            else if (data->EventKey == ImGuiKey_DownArrow)
            {
                mpInstance->mRecalledCommand++;
                if (mpInstance->mRecalledCommand >= mpInstance->mCommandHistory.size())
                {
                    mpInstance->mRecalledCommand = 0;
                }
                changeCommand = true;
            }

            if (changeCommand)
            {
                memset(mpInstance->mBuffer, 0, LUA_CON_BUFFER_SIZE);
                strcpy(mpInstance->mBuffer, mpInstance->mCommandHistory[mpInstance->mRecalledCommand].c_str());
                data->DeleteChars(0, data->BufTextLen);
                data->InsertChars(0, mpInstance->mBuffer);
                data->SelectAll();
            }
        }
        return 0;
    }
    
    void LuaConsole::Show()
    {
        // TODO: LuaConsole::Show
        if (!mbShow)
            return;

        if (Core::Input().IsKeyDown(KeyCode::ESCAPE, true))
        {
            mpInstance->mRecalledCommand = -1;
        }

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

        float myHeight =  height / 3.0f;
        
        if (mbStickToWindow)
        {
            ImGui::SetNextWindowPos(ImVec2(x, y), ImGuiCond_Always);
            ImGui::SetNextWindowSize(ImVec2(width / 3.0f, myHeight + 20), ImGuiCond_Always);
            if (!ImGui::Begin("LUA Console", &mbShow, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove
                                                    | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoCollapse))
            {
                ImGui::End();
                return;
            }
        }
        else
        {
            ImGui::SetNextWindowPos(ImVec2(x, y), ImGuiCond_FirstUseEver);
            ImGui::SetNextWindowSize(ImVec2(width / 3.0f, myHeight + 20), ImGuiCond_FirstUseEver);
            if (!ImGui::Begin("LUA Console", &mbShow))
            {
                ImGui::End();
                return;
            }
        }


        float history_height = ImGui::GetWindowHeight() - (ImGui::GetFrameHeight() * 3) - 20;
        ImGui::BeginChild("history", ImVec2(0, history_height), false, ImGuiWindowFlags_AlwaysVerticalScrollbar);
        for (int i = 0; i < mCommandHistory.size(); i++)
        {
            const char* msg = mCommandHistory[i].c_str();
            int len = strlen(msg);

            if (i == mRecalledCommand)
            {
                ImGui::TextColored(ImVec4(0.2f, 0.9f, 0.5f, 1.0f), msg);
            }
            else
            {
                ImGui::TextUnformatted(msg);
            }
        }

        if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
            ImGui::SetScrollHereY(1.0f);
            
        ImGui::EndChild();
        ImGui::Separator();
        ImGui::BeginChild("console", ImVec2(0, 40), true, ImGuiWindowFlags_NoScrollbar);
        if (ImGui::InputText("command", mBuffer, LUA_CON_BUFFER_SIZE, ImGuiInputTextFlags_EnterReturnsTrue 
                            | ImGuiInputTextFlags_CallbackHistory, LuaConsole::MyCallback))
        {
            mCommandHistory.push_back(mBuffer);
            memset(mBuffer, 0, LUA_CON_BUFFER_SIZE);
            mbNewCommand = true;

            // Doesn't keep the focus on the input text field
            // Might be another way to do it now
            ImGui::SetKeyboardFocusHere(-1);
        }

        ImGui::EndChild();
        ImGui::End();
    }

    void LuaConsole::SetShow(bool show)
    {
        mbShow = show;
    }
    
    bool LuaConsole::IsShown() const
    {
        return mbShow;
    }
    
    const std::vector<std::string>* LuaConsole::GetCommandHistory() const
    {
        return &mCommandHistory;
    }
    
    std::string LuaConsole::GetLastCommand()
    {
        return mCommandHistory.back();
    }
    
    bool LuaConsole::GetNewCommand(std::string& command)
    {
        if (mbNewCommand)
        {
            command = mCommandHistory.back();
            mbNewCommand = false;
            return true;
        }

        return false;
    }
   
    bool LuaConsole::IsStuckToWindow() const
    {
        return mbStickToWindow;
    }

    void LuaConsole::SetStickToWindow(bool stick)
    {
        mbStickToWindow = stick;
    }
}