/******************************************************************************
*	File		-	editor.cpp
*	Author		-	Joey Pollack
*	Date		-	2021/11/01 (y/m/d)
*	Mod Date	-	2021/11/01 (y/m/d)
*	Description	-	Entry point for the editor run mode.
******************************************************************************/

#include "editor.h"

#include <utils/helpers.h>
#include "panel_manager.h"
#include <core/core.h>
#include <core/version.h>
#include <utils/logger.h>
#include <internal_data/data_manager.h>
#include <gui/gui.h>
#include <dearimgui/imgui.h>

// Panels
#include "panels/world_tree.h"
#include "panels/world_view.h"
#include "panels/properties_view.h"
#include "panels/asset_browser.h"

// Tools
#include "tools/map_editor/map_editor.h"

#include <world/components.h>

// TEST STUFF
#include <world/world.h>
#include <world/entity.h>
#include <world/components.h>

using namespace lunarium::gui;

// ERROR LOG MACRO
#define LOG_ERR_AND_RETURN(result) { if (Failed(result)) { Logger::Error(LogCat, result.Description.c_str()); return result; } } 

namespace lunarium
{
namespace editor
{
    uint32_t Editor::LogCat = -1;
    
    Editor::Editor()
        : mDoNewProject(false), mDoOpenProject(false),
        mDoSaveProject(false), mDoSaveAs(false), mNextWindowID(0), mpMapEditor(nullptr)
    {
    }

    OpRes Editor::Initialize()
    {
        LogCat = Logger::RegisterCategory("EDITOR");

        // Initialize internal data
        DataManager::Initialize();

        ImGui::GetIO().ConfigWindowsMoveFromTitleBarOnly = true;

        // Init editor panels
        mAboutPanel.SetOpen(false);

        OpRes res = mPanelManager.Initialize(this, "Lunarium editor", true).LogIfFailed(LogCat);
        if (Failed(res))
        {
            return res;
        }

        mPanelManager.AddPanel(new AssetBrowser("", this), mPanels.AssetBrowser).LogIfFailed(LogCat);
        mPanelManager.AddPanel(new WorldTree(), mPanels.WorldTree).LogIfFailed(LogCat);
        mPanelManager.AddPanel(new WorldView(), mPanels.WorldView).LogIfFailed(LogCat);
        mPanelManager.AddPanel(new PropertiesView(), mPanels.PropertiesView).LogIfFailed(LogCat);

        return OpRes::OK();
    }
    
    void Editor::Shutdown()
    {


        DataManager::Shutdown();
        mPanelManager.Shutdown();
    }
    
    void Editor::OnTick(double delta)
    {
        // Panels
        mPanelManager.OnTick(delta);

        // Tools
        if (mpMapEditor)
        {
            mpMapEditor->OnTick(delta);
        }

        HandleMenuEvents();
    }
    
    void Editor::OnRender(lunarium::IGraphics* g)
    {
        DoMainMenu();
        //DoStatusBar();
        RenderWindow();
        
        //mPanelManager.OnRender(g);



        if (mpMapEditor)
        {
            mpMapEditor->OnRender(g);
        }

        if (mAboutPanel.IsOpen())
        {
            mAboutPanel.DoFrame();
        }
    }

    uint32_t Editor::GetLogCat() const
    {
        return LogCat;
    }
    
    unsigned int Editor::GetNextWindowID()
    {
        return ++mNextWindowID;
    }

    
    bool Editor::IsToolOpen(ToolType type) const
    {
        switch (type)
        {
            case ToolType::TT_MAP_EDITOR:
            {
                if (!mpMapEditor)
                    return false;

                return mpMapEditor->IsOpen();
            }
        }

        Logger::Warn(LogCat, "And unknown ToolType was passed into Editor::IsToolOpen: %n", type);
        return false;
    }

    ////////////////////////////////////////////////////////////
    //				HELPER METHODS
    ////////////////////////////////////////////////////////////

    std::filesystem::path Editor::GetAssetBrowserLocation()
    {
        return mProject.GetAssetDirectory() / ((AssetBrowser*)mPanelManager.GetPanel(mPanels.AssetBrowser))->GetSelectedDirectory();
    }

    Project* Editor::GetProject()
    {
        return &mProject;
    }
    
    void Editor::RenderWindow()
    {
        ImGuiViewport* Viewport = ImGui::GetWindowViewport();
        ImGui::SetNextWindowPos( Viewport->WorkPos );
        ImGui::SetNextWindowSize( Viewport->WorkSize );
        ImGui::SetNextWindowViewport( Viewport->ID );
        ImGuiWindowFlags WindowFlags = 0;
        WindowFlags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDocking;
        WindowFlags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;

        ImGui::PushStyleVar( ImGuiStyleVar_WindowRounding, 0.0f );
        ImGui::PushStyleVar( ImGuiStyleVar_WindowBorderSize, 0.0f );
        ImGui::PushStyleVar( ImGuiStyleVar_WindowPadding, ImVec2( 0.0f, 0.0f ) );

        ImGui::Begin("Lunarium Editor", nullptr, WindowFlags);
        ImGui::PopStyleVar(3);
        
        mPanelManager.MakeDockSpaces();

        ImGui::End();

        mPanelManager.RenderPanels();
    }


    void Editor::DestroyTools()
    {
        mpMapEditor->Shutdown();
        delete mpMapEditor;
        mpMapEditor = nullptr;
    }

    void Editor::HandleMenuEvents()
    {
    }

    ////////////////////////////////////////////////////////////
    //				MENU BAR
    ////////////////////////////////////////////////////////////
    void Editor::DoMainMenu()
    {
        ImGui::BeginMainMenuBar();
        
            // File
            if (ImGui::BeginMenu("File"))
            {
                if (ImGui::MenuItem("New Project"))
                {
                    std::filesystem::path outPath;

                    // prepare filters for the dialog
                    const FileSystem::FilterItem filterItem[1] = {{"Lunarium Project File", "lproj"}};

                    // show the dialog
                    FileSystem::DialogResult result = FileSystem::SaveFileDialog(outPath, filterItem, 1); 
                    if (result == FileSystem::DialogResult::OK) 
                    {
                        //std::filesystem::path the_path = outPath.get();
                        Logger::Info(LogCat, "Generating new project at %s", outPath.string().c_str());
                        OpRes result = mProject.GenerateProject(outPath.filename().string(), outPath.parent_path());
                        if (Failed(result))
                        {
                            Logger::Error(LogCat, "Could not create a new project: %s", result.Description);
                        }
                        else
                        {
                            ((AssetBrowser*)mPanelManager.GetPanel(mPanels.AssetBrowser))->
                                        SetAssetDirectory(outPath.parent_path() / std::filesystem::path("contents/assets"));
                        }

                    } 
                    else if (result == FileSystem::DialogResult::CANCEL) 
                    {
                        Logger::Info(LogCat, "User cancelled project create");
                    } 
                    else 
                    {
                        Logger::Error(LogCat, "Error getting project file location: %s", FileSystem::GetError().c_str());
                    }
                    
                }

                if (ImGui::MenuItem("Open Project"))
                {
                    std::filesystem::path outPath;

                    // prepare filters for the dialog
                    FileSystem::FilterItem filterItem[1] = {{"Lunarium Project File", "lproj"}};

                    // show the dialog
                    FileSystem::DialogResult result = FileSystem::OpenFileDialog(outPath, filterItem, 1);
                    if (result == FileSystem::DialogResult::OK) 
                    {
                         Logger::Info(LogCat, "Opening project: %s", outPath.string().c_str());

                        // Open project at mpPath
                        if (Failed(mProject.LoadProject(outPath).LogIfFailed(Editor::LogCat)))
                        {
                            Logger::Error(LogCat, "Failed to load project: %s", outPath.string().c_str());
                        }
                        else
                        {
                            ((AssetBrowser*)mPanelManager.GetPanel(mPanels.AssetBrowser))->
                                    SetAssetDirectory(outPath.parent_path() / std::filesystem::path("contents/assets"));
                        }
                    

                    } 
                    else if (result == FileSystem::DialogResult::CANCEL) 
                    {
                        Logger::Info(LogCat, "User cancelled project open");
                    } 
                    else 
                    {
                        Logger::Error(LogCat, "Error getting project file location: %s", FileSystem::GetError().c_str());
                    }
                }

                if (ImGui::MenuItem("Save Project"))
                {
                    mProject.SaveProject();
                }

                ImGui::Separator();

                if (ImGui::MenuItem("Exit"))
                {
                    Core::GetInstance().SignalShutdown();
                }
                ImGui::EndMenu();
            }

            if (ImGui::BeginMenu("View"))
            {
                if (ImGui::BeginMenu("Styles"))
                {
                    if (ImGui::MenuItem("Classic"))
                    {
                        GUI::GetInstance().SetStyle(GuiStyle::STYLE_DEFAULT_CLASSIC);
                    }

                    if (ImGui::MenuItem("Default Dark"))
                    {
                        GUI::GetInstance().SetStyle(GuiStyle::STYLE_DEFAULT_DARK);
                    }

                    if (ImGui::MenuItem("Default Light"))
                    {
                        GUI::GetInstance().SetStyle(GuiStyle::STYLE_DEFAULT_LIGHT);
                    }

                    ImGui::Separator();

                    if (ImGui::MenuItem("Deep Dark"))
                    {
                        GUI::GetInstance().SetStyle(GuiStyle::STYLE_DEEP_DARK);
                    }

                    if (ImGui::MenuItem("Red Dark"))
                    {
                        GUI::GetInstance().SetStyle(GuiStyle::STYLE_RED_DARK);
                    }

                    if (ImGui::MenuItem("Green Blue"))
                    {
                        GUI::GetInstance().SetStyle(GuiStyle::STYLE_GREEN_BLUE);
                    }

                    if (ImGui::MenuItem("OverShifted Dark"))
                    {
                        GUI::GetInstance().SetStyle(GuiStyle::STYLE_OVERSHIFTED_DARK);
                    }

                    if (ImGui::MenuItem("Charcoal"))
                    {
                        GUI::GetInstance().SetStyle(GuiStyle::STYLE_CHARCOAL);
                    }

                    if (ImGui::MenuItem("Corporate Gray"))
                    {
                        GUI::GetInstance().SetStyle(GuiStyle::STYLE_CORPORATE_GRAY);
                    }

                    if (ImGui::MenuItem("Corporate Gray 3D"))
                    {
                        GUI::GetInstance().SetStyle(GuiStyle::STYLE_CORPORATE_GRAY_3D);
                    }

                    ImGui::EndMenu();
                }

                ImGui::EndMenu();
            }

            if (ImGui::BeginMenu("Windows"))
            {
                if (ImGui::MenuItem("Reset Window Docking"))
                {
                    mPanelManager.ResetDocking();
                }
                ImGui::Separator();

                HandleOpenPanel("Asset Browser", mPanels.AssetBrowser);
                HandleOpenPanel("World Tree", mPanels.WorldTree);
                HandleOpenPanel("World View", mPanels.WorldView);
                HandleOpenPanel("Properties", mPanels.PropertiesView);

                ImGui::EndMenu();
            }

            // Tools
            if (ImGui::BeginMenu("Tools"))
            {
                if (ImGui::MenuItem("Map Editor"))
                {
                    if (!mpMapEditor)
                    {
                        mpMapEditor = new MapEditor;
                        mpMapEditor->Initialize(this);
                    }

                    mpMapEditor->Open();
                }
                ImGui::EndMenu();
            }

            if (ImGui::BeginMenu("Help"))
            {
                if (ImGui::MenuItem("About"))
                {
                    mAboutPanel.SetOpen(true);
                }
                
                ImGui::EndMenu();
            }

        ImGui::EndMainMenuBar();
    }


    void Editor::HandleOpenPanel(const char* name, uint32_t id)
    {
        if (ImGui::MenuItem(name)) 
        {
            mPanelManager.OpenPanel(id);
        }
    }

    void Editor::DoStatusBar()
    {
        const ImGuiViewport* viewport = ImGui::GetMainViewport();
        ImGui::SetNextWindowViewport(viewport->ID);
        float height = viewport->WorkSize.y * 0.035f;
        float ypos = (viewport->WorkPos.y + viewport->WorkSize.y) - height;
        ImGui::SetNextWindowSize(ImVec2(viewport->WorkSize.x, height), ImGuiCond_Always);
        ImGui::SetNextWindowPos(ImVec2(viewport->WorkPos.x, ypos), ImGuiCond_Always);
        ImGui::PushStyleVar( ImGuiStyleVar_WindowRounding, 0.0f );
        ImGui::PushStyleVar( ImGuiStyleVar_WindowBorderSize, 0.1f );
        ImGui::PushStyleVar( ImGuiStyleVar_WindowPadding, ImVec2( 0.0f, 0.0f ) );
        ImGui::Begin("status bar", nullptr, ImGuiWindowFlags_NoCollapse 
                                 | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize
                                 | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoDocking );

        if (ImGui::BeginTable("status", 3, ImGuiTableFlags_BordersInnerV))
        {
            ImGui::AlignTextToFramePadding();
            ImGui::TableNextColumn();
            ImGui::Text("Lunarium (%s)", Version::GetVersion().ToString().c_str());
            ImGui::TableNextColumn();
            ImGui::Text("Testing");
            ImGui::TableNextColumn();
            ImGui::Text("Status Bar");
            ImGui::EndTable();
        }

        ImGui::PopStyleVar(3);
        ImGui::End();
    }

}
}