/******************************************************************************
*	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 "panel_manager.h"
#include <core/core.h>
#include <core/version.h>
#include <utils/logger.h>
#include <internal_data/dataManager.h>
#include <gui/dearimgui/imgui.h>

// Panels
#include "panels/worldTree.h"
#include "panels/worldView.h"
#include "panels/propertiesView.h"
#include "panels/assetBrowser.h"

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

using namespace lunarium::gui;

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

namespace lunarium
{
namespace editor
{
    uint32_t Editor::LogCat = -1;
    
    Editor::Editor()
        : mpPath(nullptr), 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("")).LogIfFailed(LogCat);
        mPanelManager.AddPanel(new WorldTree()).LogIfFailed(LogCat);
        mPanelManager.AddPanel(new WorldView()).LogIfFailed(LogCat);
        mPanelManager.AddPanel(new 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();
        }
        
        if (mFileBrowser.IsOpen())
        {
            mFileBrowser.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::Log(LogCat, LogLevel::WARNING, "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(gui::PanelType::PT_ASSET_BROWSER))->GetSelectedDirectory();
    }
    
    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()
    {
        ///////////////////////////
        // FILE
        if (mDoNewProject)
        {
            if (mFileBrowser.GetResult() == FileBrowser::Result::OK)
            {
                mpPath = mFileBrowser.GetSelectedItem();
                Logger::Log(LogCat, LogLevel::INFO, "Generating new project at %s", mpPath->string().c_str());

                // Generate new project at mpPath
                OpRes result = mProject.GenerateProject(mpPath->filename().string(), mpPath->parent_path());
                if (Failed(result))
                {
                    Logger::Log(LogCat, LogLevel::ERROR, "Could not create a new project: %s", result.Description);
                }
                ((AssetBrowser*)mPanelManager.GetPanel(PanelType::PT_ASSET_BROWSER))->SetAssetDirectory(*mpPath / std::filesystem::path("contents/assets"));
                mDoNewProject = false;
            }
            else if (mFileBrowser.GetResult() == FileBrowser::Result::CANCEL)
            {
                Logger::Log(LogCat, LogLevel::INFO, "New Project operation cancelled");
                mDoNewProject = false;
            }
                         
        }

        if (mDoOpenProject)
        {
            if (mFileBrowser.GetResult() == FileBrowser::Result::OK)
            {
                mpPath = mFileBrowser.GetSelectedItem();
                Logger::Log(LogCat, LogLevel::INFO, "Opening project: %s", mpPath->string().c_str());

                // Open project at mpPath
                if (Failed(mProject.LoadProject(*mpPath).LogIfFailed(Editor::LogCat)))
                {
                    mDoOpenProject = false;
                    return;
                }
                ((AssetBrowser*)mPanelManager.GetPanel(PanelType::PT_ASSET_BROWSER))->SetAssetDirectory(mpPath->parent_path() / std::filesystem::path("contents/assets"));
                mDoOpenProject = false;
            }
            else if (mFileBrowser.GetResult() == FileBrowser::Result::CANCEL)
            {
                Logger::Log(LogCat, LogLevel::INFO, "Open Project operation cancelled");
                mDoOpenProject = false;
            }
             
        }

        if (mDoSaveProject)
        {
            if (!mProject.IsLoaded())
            {
                mDoSaveAs = true;
                mDoSaveProject = false;
            }
            else
            {
                mProject.SaveProject();
                mDoSaveProject = false;
            }
        }

        if (mDoSaveAs)
        {

            mDoSaveAs = false;
        }
        ///////////////////////////
        
    }

    ////////////////////////////////////////////////////////////
    //				MENU BAR
    ////////////////////////////////////////////////////////////
    void Editor::DoMainMenu()
    {
        ImGui::BeginMainMenuBar();
        
            // File
            if (ImGui::BeginMenu("File"))
            {
                if (ImGui::MenuItem("New Project"))
                {
                    mDoNewProject = true;
                    mFileBrowser.SetSelectionMode(FileBrowser::SelectionMode::FILES_ONLY);
                    mFileBrowser.SetPrompt("Pick a location and name for the project");
                    if (!mFileBrowser.OpenInDirectory(""))
                    {
                        mDoNewProject = false;
                        Logger::Log(LogCat, LogLevel::ERROR, "Could not open the File Browser");
                    }
                    
                }

                if (ImGui::MenuItem("Open Project"))
                {
                    mDoOpenProject = true;
                    mFileBrowser.SetSelectionMode(FileBrowser::SelectionMode::FILES_ONLY);
                    mFileBrowser.SetPrompt("Pick a location and name for the project");
                    if (!mFileBrowser.OpenInDirectory(""))
                    {
                        mDoOpenProject = false;
                        Logger::Log(LogCat, LogLevel::ERROR, "Could not open the File Browser");
                    }
                }

                if (ImGui::MenuItem("Save Project"))
                {
                    mDoSaveProject = true;
                }

                if (ImGui::MenuItem("Save Project As"))
                {
                    mDoSaveAs = true;
                }

                ImGui::Separator();

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

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

                HandleOpenPanel("Asset Browser", gui::PanelType::PT_ASSET_BROWSER);
                HandleOpenPanel("World Tree", gui::PanelType::PT_WORLD_TREE);
                HandleOpenPanel("World View", gui::PanelType::PT_WORLD_VIEW);
                HandleOpenPanel("Properties", gui::PanelType::PT_PROPERTIES_VIEW);

                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, gui::PanelType type)
    {
        if (ImGui::MenuItem(name)) 
        {
            mPanelManager.OpenPanel(type);
        }
    }

    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();
    }

}
}