/*
	ApplicationFramework
	by John Ryland
	Copyright (c) 2023
*/

////////////////////////////////////////////////////////////////////////////////////
//	Main Window

#include "MainWindow.h"
#include "Acknowledgements.h"
#include "Image.h"
#include "IRenderSystem.h"
#include "Application.h"
#include "imgui.h"

// #define FILE_DIALOGS    1
#ifdef FILE_DIALOGS
// Different file dialogs
#  include "nfd.h"
#  include "ImFileDialog.h"
#  include "L2DFileDialog.h"
#endif

namespace ApplicationFramework {

MainWindow::MainWindow(IApplication& app, int width, int height, const char* title)
    : Window(app, width, height, title)
{
#ifdef FILE_DIALOGS
	// ImFileDialog requires you to set the CreateTexture and DeleteTexture
	ifd::FileDialog::Instance().CreateTexture = [&app](uint8_t* data, int w, int h, char fmt) -> void* {
        ApplicationFramework::Image textureImage;
        textureImage.Init(data, w, h, 4);
        return app.RenderSystem()->CreateTexture(textureImage);
	};
	ifd::FileDialog::Instance().DeleteTexture = [&app](void* tex) {
        return app.RenderSystem()->DestroyTexture(tex);
	};
#endif
}

// virtual
void MainWindow::Update()
{
    ParentClass::Update();

    // Dockspace app
    ImGui::DockSpaceOverViewport();

    ShowMenus();
    ShowOverlay();
    ShowStyleEditor();

    if (show_demo_window)
        ImGui::ShowDemoWindow(&show_demo_window);
    if (show_app_metrics)
        ImGui::ShowMetricsWindow(&show_app_metrics);
    if (show_app_debug_log)
        ImGui::ShowDebugLogWindow(&show_app_debug_log);
    if (show_app_stack_tool)
        ImGui::ShowStackToolWindow(&show_app_stack_tool);
    if (show_app_about)
        ImGui::ShowAboutWindow(&show_app_about);
    if (show_acknowledgements)
        Acknowledgements::Get().Show(&show_acknowledgements);

#ifdef FILE_DIALOGS
    // File dialog
    static char buffer[512] = { '.', '/', 0 };
    if (FileDialog::file_dialog_open)
        FileDialog::ShowFileDialog(&FileDialog::file_dialog_open, buffer, sizeof(buffer), FileDialog::FileDialogType::OpenFile);
    //FileDialog::ShowFileDialog(&fopendia, buffer, std::size(buffer));
#endif
}

void MainWindow::AddMenus()
{
    if (ImGui::BeginMenu("File"))
    {
        ShowFileMenu();
        ImGui::EndMenu();
    }
    if (ImGui::BeginMenu("Edit"))
    {
        if (ImGui::MenuItem("Undo", "CTRL+Z")) {}
        if (ImGui::MenuItem("Redo", "CTRL+Y", false, false)) {}  // Disabled item
        ImGui::Separator();
        if (ImGui::MenuItem("Cut", "CTRL+X")) {}
        if (ImGui::MenuItem("Copy", "CTRL+C")) {}
        if (ImGui::MenuItem("Paste", "CTRL+V")) {}
        ImGui::EndMenu();
    }
}

void MainWindow::ShowMenus()
{
    if (ImGui::BeginMainMenuBar())
    {
        AddMenus();

        if (ImGui::BeginMenu("Tools"))
        {
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
            const bool has_debug_tools = true;
#else
            const bool has_debug_tools = false;
#endif
            ImGui::MenuItem("Status Overlay", NULL, &show_app_overlay);
            ImGui::MenuItem("Metrics/Debugger", NULL, &show_app_metrics, has_debug_tools);
            ImGui::MenuItem("Debug Log", NULL, &show_app_debug_log, has_debug_tools);
            ImGui::MenuItem("Stack Tool", NULL, &show_app_stack_tool, has_debug_tools);
            ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor);
            ImGui::MenuItem("Demo Window", NULL, &show_demo_window);
            ImGui::EndMenu();
        }
    
        if (ImGui::BeginMenu("Help"))
        {
            ImGui::MenuItem("Acknowledgements", NULL, &show_acknowledgements);
            ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about);
            ImGui::EndMenu();
        }

        ImGui::EndMainMenuBar();
    }

#ifdef FILE_DIALOGS
    if (ifd::FileDialog::Instance().IsDone("ShaderOpenDialog")) {
        if (ifd::FileDialog::Instance().HasResult()) {
            const std::vector<std::filesystem::path>& res = ifd::FileDialog::Instance().GetResults();
            for (const auto& r : res) // ShaderOpenDialog supports multiselection
                printf("OPEN[%s]\n", r.u8string().c_str());
        }
        ifd::FileDialog::Instance().Close();
    }
#endif
}

// Note that shortcuts are currently provided for display only
// (future version will add explicit flags to BeginMenu() to request processing shortcuts)
void MainWindow::ShowFileMenu()
{
    //ImGui::MenuItem("(demo menu)", NULL, false, false);
    if (ImGui::MenuItem("New")) {}

    if (ImGui::MenuItem("Open", "Ctrl+O"))
    {
#ifdef FILE_DIALOGS
        ifd::FileDialog::Instance().Open("ShaderOpenDialog", "Open a shader", "Image file (*.png;*.jpg;*.jpeg;*.bmp;*.tga){.png,.jpg,.jpeg,.bmp,.tga},.*", true);
#endif
    }

    if (ImGui::BeginMenu("Open Recent"))
    {
        ImGui::MenuItem("fish_hat.c");
        ImGui::MenuItem("fish_hat.inl");
        ImGui::MenuItem("fish_hat.h");
        if (ImGui::BeginMenu("More.."))
        {
            ImGui::MenuItem("Hello");
            ImGui::MenuItem("Sailor");
            if (ImGui::BeginMenu("Recurse.."))
            {
                ShowFileMenu();
                ImGui::EndMenu();
            }
            ImGui::EndMenu();
        }
        ImGui::EndMenu();
    }

    if (ImGui::MenuItem("Save", "Ctrl+S"))
    {
#ifdef FILE_DIALOGS
        nfdchar_t *outPath;
        nfdresult_t res = NFD_OpenDialog("*.pro", ".", &outPath);
#endif
    }

    if (ImGui::MenuItem("Save As.."))
    {
#ifdef FILE_DIALOGS
        FileDialog::file_dialog_open = true;
#endif
    }

    ImGui::Separator();
    if (ImGui::BeginMenu("Options"))
    {
        static bool enabled = true;
        ImGui::MenuItem("Enabled", "", &enabled);
        ImGui::BeginChild("child", ImVec2(0, 60), true);
        for (int i = 0; i < 10; i++)
            ImGui::Text("Scrolling Text %d", i);
        ImGui::EndChild();
        static float f = 0.5f;
        static int n = 0;
        ImGui::SliderFloat("Value", &f, 0.0f, 1.0f);
        ImGui::InputFloat("Input", &f, 0.1f);
        ImGui::Combo("Combo", &n, "Yes\0No\0Maybe\0\0");
        ImGui::EndMenu();
    }

    if (ImGui::BeginMenu("Colors"))
    {
        float sz = ImGui::GetTextLineHeight();
        for (int i = 0; i < ImGuiCol_COUNT; i++)
        {
            const char* name = ImGui::GetStyleColorName((ImGuiCol)i);
            ImVec2 p = ImGui::GetCursorScreenPos();
            ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32((ImGuiCol)i));
            ImGui::Dummy(ImVec2(sz, sz));
            ImGui::SameLine();
            ImGui::MenuItem(name);
        }
        ImGui::EndMenu();
    }

    // Here we demonstrate appending again to the "Options" menu (which we already created above)
    // Of course in this demo it is a little bit silly that this function calls BeginMenu("Options") twice.
    // In a real code-base using it would make senses to use this feature from very different code locations.
    if (ImGui::BeginMenu("Options")) // <-- Append!
    {
        static bool b = true;
        ImGui::Checkbox("SomeOption", &b);
        ImGui::EndMenu();
    }

    if (ImGui::BeginMenu("Disabled", false)) // Disabled
    {
        IM_ASSERT(0);
    }
    if (ImGui::MenuItem("Checked", NULL, true)) {}
    if (ImGui::MenuItem("Quit", "Alt+F4")) {}
}

void MainWindow::ShowOverlay()
{
    bool* p_open = &show_app_overlay;
    if (!*p_open)
        return;
    ImGuiIO& io = ImGui::GetIO();
    ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
    ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background

    ImVec2 pos = ImGui::GetMainViewport()->Pos;
    ImVec2 siz = ImGui::GetMainViewport()->Size;
    pos = ImVec2(pos.x + siz.x * 0.67f, pos.y + siz.y * 0.15f);
    ImGui::SetNextWindowPos(pos, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));

    if (ImGui::Begin("Overlay", p_open, window_flags))
    {
        ImGui::Text("Mouse Position:");
        if (ImGui::IsMousePosValid())
            ImGui::Text("%.1f,%.1f", io.MousePos.x, io.MousePos.y);
        else
            ImGui::Text("<invalid>");
        ImGui::Separator();
        ImGui::Text("Average frame rate:");
        ImGui::Text("%.1f fps (%.1f ms)", ImGui::GetIO().Framerate, 1000.0f / ImGui::GetIO().Framerate);
        if (ImGui::BeginPopupContextWindow())
        {
            if (p_open && ImGui::MenuItem("Close"))
                *p_open = false;
            ImGui::EndPopup();
        }
    }
    ImGui::End();
}

void MainWindow::ShowStyleEditor()
{
    if (show_app_style_editor)
    {
        ImGui::Begin("UI Style Editor", &show_app_style_editor);
        ImGui::ShowStyleEditor();
        ImGui::End();
    }
}

} // ApplicationFramework namespace
