/******************************************************************************
*	File		-	map_editor.h
*	Author		-	Joey Pollack
*	Date		-	2022/01/31 (y/m/d)
*	Mod Date	-	2022/01/31 (y/m/d)
*	Description	-	The tile map editor tool. Controls subwindows/panels.
******************************************************************************/

#include "map_editor.h"

#include <core/core.h>
#include <graphics/graphics.h>
#include <assets/types/image.h>
#include <editor/editor.h>
#include <gui/panel.h>
#include <dearimgui/imgui.h>
#include <editor/contents/content_manager.h>
#include <editor/contents/tile_set.h>
#include <editor/contents/tile_map.h>
#include <utils/helpers.h>

// Panels
#include "panels/map_canvas.h"
#include "panels/tile_set_view.h"

// TEMP
#include <utils/stb/stb_image.h>

namespace lunarium { namespace editor
{
    MapEditor::MapEditor()
        : mpEditor(nullptr), mIsOpen(false), mMapLoaded(false), mImportTileSet(false), mTileSetNextID(0), mpMap(nullptr)
    {
        
    }


    OpRes MapEditor::Initialize(Editor* editor)
    {
        if (mpEditor)
        {
            return OpRes::Fail("MapEditor is already initialized");
        }

        mpEditor = editor;
        if (Failed(mPanelManager.Initialize(mpEditor, "Map Editor").LogIfFailed(mpEditor->GetLogCat(), "Map Editor - ")))
        {
            return OpRes::Fail("Could not initialize the panel manager!");
        }

        mPanelManager.AddPanel(new MapCanvas(this), mPanels.MapCanvas).LogIfFailed(mpEditor->GetLogCat());
        mPanelManager.AddPanel(new TileSetView(this), mPanels.TileSetView).LogIfFailed(mpEditor->GetLogCat());

        Open();

        std::vector<EditorAsset*> tile_sets;
        ContentManager::GetInstance().GetAllAssetsByType(tile_sets, AssetType::EATYPE_TILE_SET);
        for (int i = 0; i < tile_sets.size(); i++)
        {
            TileSet* ts = (TileSet*) tile_sets[i];
            mTileSets[ts->GetTileSetID()] = ts;
            //((TileSetView*)mPanelManager.GetPanel(gui::PanelType::PT_TILE_SET_VIEW))->SetTileSet((TileSet*)tile_sets[i]);
        }

        return OpRes::OK();
    }

    void MapEditor::Shutdown()
    {
        mpEditor = nullptr;

        // Free Tilesets
        mPanelManager.Shutdown();
        for (auto i = mTileSets.begin(); i != mTileSets.end(); i++)
        {
            delete i->second->GetImage();
            delete i->second;
        }

        mTileSets.clear();
    }

    void MapEditor::OnTick(double delta)
    {
        HandleMenuEvents();

        mPanelManager.OnTick(delta);
    }

    bool MapEditor::OnRender(lunarium::IGraphics* g)
    {
        if (!mIsOpen)
        {
            Close();
            return false;
        }


        ImGui::SetNextWindowSize(ImVec2(800, 500), ImGuiCond_FirstUseEver);
        if (!ImGui::Begin("Map Editor", &mIsOpen, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_MenuBar))
        {
            mPanelManager.MakeDockSpaces();
            Close();
            ImGui::End();
            return false;
        }
        DoMenu();

        mPanelManager.MakeDockSpaces();

        ImGui::End();

        mPanelManager.RenderPanels();
        return true;
    }


    void MapEditor::Open()
    {
        if (mIsOpen)
        {
            return;
        }
 
        mIsOpen = true;
    }

    void MapEditor::Close()
    {        
        mIsOpen = false;
    }

    bool MapEditor::IsOpen() const
    {
        return mIsOpen;
    }


    void MapEditor::NewMap()
    {
        if (mpMap && mpMap->IsDirty())
        {
            // TODO: Do last chance save
        }

        delete mpMap;
        // HACK: Hardcoding the tile size to 16, 16
        mpMap = new TileMap({16, 16});

        // HACK: Map size hardcoded for testing
        mpMap->ResizeMap({50, 50});
        mpMap->ClearMap();

        // Add all tilesets that match the Map's tile size
        ((TileSetView*)mPanelManager.GetPanel(mPanels.TileSetView))->ClearTileSets();
        for (auto iter = mTileSets.begin(); iter != mTileSets.end(); iter++)
        {
            if (iter->second->GetTileSize() == mpMap->GetTileSize())
            {
                mpMap->AddTileSet(iter->second->GetTileSetID(), iter->second);
                ((TileSetView*)mPanelManager.GetPanel(mPanels.TileSetView))->AddTileSet(iter->second);   
            }
        }

        ((MapCanvas*)mPanelManager.GetPanel(mPanels.MapCanvas))->SetTileMap(mpMap);
    }

    OpRes MapEditor::LoadMap(std::string map)
    {
        {
            // TODO: Do last chance save if needed

            // TODO: Clean up currrent map
        }

        // TODO: Clear out the tileset view

        // TODO: Load the new map
        
        // TODO: Add all tilesets that match the Map's tile size
        //       to the Map and the TileSetView panel

        // TODO: Set the map for the MapCanvas panel

        return OpRes::Fail("MapEditor::LoadMap not implemented");
    }

    void MapEditor::SaveMap()
    {
        
    }

    bool MapEditor::IsMapLoaded() const
    {
        return mMapLoaded;
    }

    const std::map<int, TileSet*>* MapEditor::GetTileSets() const
    {
        return &mTileSets;
    }

    ////////////////////////////////////////////////////////////
    //				HELPERS
    ////////////////////////////////////////////////////////////
    void MapEditor::DoMenu()
    {
        ImGui::BeginMenuBar();

        if (ImGui::BeginMenu("File"))
        {
            if (ImGui::MenuItem("New Map"))
            {
                NewMap();
            }
            
            ImGui::Separator();
            if (ImGui::MenuItem("Import Tile Set"))
            {
                std::filesystem::path outPath;

                // prepare filters for the dialog
                FileSystem::FilterItem filterItem[3] = {{"Image file", "png"}, {"Image File", "jpg"}, {"Image File", "jpeg"}};

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

                    uint64_t id = 0;
                    ContentManager::GetInstance().ImportFile(outPath, mpEditor->GetAssetBrowserLocation() /  outPath.filename(), AssetType::EATYPE_TILE_SET, id).LogIfFailed(Editor::LogCat);

                    TileSet* ts = (TileSet*)ContentManager::GetInstance().GetAsset(id);
                    ts->SetTileSize({16, 16});      // NOTE: Hardcoding the tile size for testing
                    ts->SetTileSetID(mTileSetNextID);
                    mTileSets[mTileSetNextID] = ts;
                    mTileSetNextID++;

                    // Check if the tile set can be used on the current map
                    if (mpMap && mpMap->GetTileSize() == ts->GetTileSize())
                    {
                        mpMap->AddTileSet(ts->GetTileSetID(), ts);
                        ((TileSetView*)mPanelManager.GetPanel(mPanels.TileSetView))->AddTileSet(ts);
                    }
                }
                   
            }

            ImGui::Separator();
            if (ImGui::MenuItem("Exit"))
            {
                Close();
            }
            
            ImGui::EndMenu();
        }

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

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

                ImGui::EndMenu();
            }


        ImGui::EndMenuBar();
    }

    void MapEditor::HandleMenuEvents()
    {

    }

    
    void MapEditor::ChangeSelectedTile(TileRef tile)
    {
        ((MapCanvas*)mPanelManager.GetPanel(mPanels.MapCanvas))->SetSelectedTile(tile);
    }
}}
