/******************************************************************************
*	File		-	tile_set_view.cpp
*	Author		-	Joey Pollack
*	Date		-	2022/02/16 (y/m/d)
*	Mod Date	-	2022/02/16 (y/m/d)
*	Description	-	panel for viewing the current tile set
******************************************************************************/

#include "tile_set_view.h"
#include "../map_editor.h"
#include <editor/contents/tile_set.h>
#include <assets/types/image.h>
#include <editor/editor.h>
#include <core/core.h>
#include <graphics/graphics.h>
#include <sstream>

#include <utils/stb/std_image_write.h>

namespace lunarium { namespace editor 
{
    TileSetView::TileSetView(MapEditor* editor)
        : Panel("Tile Set View", gui::PanelDockZone::DDZ_RIGHT, true), 
            mpEditor(editor), mpSelectedTileSet(nullptr), mpViewImage(nullptr), mFrameBuffer(-1),
            mViewOffset({0, 0}), mViewZoom(1.0f), mMouseDown(false)
    {
        
    }

    void TileSetView::Update(float delta)
    {
        if (ImGui::GetIO().MouseDown[ImGuiMouseButton_Left] && !mMouseDown)
        {
            mMouseDown = true;
            float x = ImGui::GetMousePos().x;
            float y = ImGui::GetMousePos().y;

            // Adjust for window pos
            x -= mWorkAreaPos.X;
            y -= mWorkAreaPos.Y;

            // Check that it's within the window
            bool is_in_window = x >= 0.0f && x < mWorkAreaSize.X && y >= 0.0f && y < mWorkAreaSize.Y;

            if (is_in_window && mpSelectedTileSet)
            {
                // Adjust for scrolling
                x += mScrollOffset.X;
                y += mScrollOffset.Y;

                // Find selected tile       
                mSelectedTile.X = x / mpSelectedTileSet->GetTileSize().Width;
                mSelectedTile.Y = y / mpSelectedTileSet->GetTileSize().Height;

                // Notify the editor that the selected tile has changed
                mpEditor->ChangeSelectedTile({ mpSelectedTileSet->GetTileSetID(), mSelectedTile });

                Invalidate();
            }
        }

        if (!ImGui::GetIO().MouseDown[ImGuiMouseButton_Left] && mMouseDown)
        {
            mMouseDown = false;
        }

        if (mInvalidate)
        {
            if (mpSelectedTileSet)
            {
                if (mFrameBuffer == -1)
                {
                    mFrameBuffer = Core::Graphics().CreateRenderTexture(mpSelectedTileSet->GetImage()->GetWidth(), mpSelectedTileSet->GetImage()->GetHeight(), 4);
                }

                Color prev = Core::Graphics().GetClearColor();
                Core::Graphics().SetClearColor(Color::Transparent());
                Core::GetInstance().BeginRenderToTexture(mFrameBuffer).LogIfFailed(Editor::LogCat);

                mpSelectedTileSet->Render(&Core::Graphics());
                
                // Draw selected tile highlight
                if (mSelectedTile.X >= 0 && mSelectedTile.Y >= 0)
                {
                    Rectangle selection = mpSelectedTileSet->GetTileRect(mSelectedTile);                    
                    Core::Graphics().DrawBox(selection, Color::Red(), 1.5f);
                }

                mpViewImage = Core::GetInstance().EndRenderToTexture();
                Core::Graphics().SetClearColor(prev);

                // //stbi_flip_vertically_on_write(1);
                // stbi_write_png("tileset_test_image.png", mpViewImage->GetWidth(), mpViewImage->GetHeight(), 4, 
                //                 mpViewImage->GetData(), mpViewImage->GetWidth() * 4);
            }
            mInvalidate = false;
        }
    }

    bool TileSetView::DoFrame()
    {
        if (!mIsOpen)
            return false;

        ImGui::PushStyleVar( ImGuiStyleVar_WindowRounding, 0.0f );
        ImGui::PushStyleVar( ImGuiStyleVar_WindowBorderSize, 0.0f );
        ImGui::PushStyleVar( ImGuiStyleVar_WindowPadding, ImVec2( 0.0f, 0.0f ) );
        if (!ImGui::Begin(GetName(), &mIsOpen, ImGuiWindowFlags_HorizontalScrollbar))
        {
            ImGui::PopStyleVar(3);
            ImGui::End();
            return false;
        }
        ImGui::PopStyleVar(3);

        ImVec2 window_size = ImGui::GetWindowSize();

        float child_height = ImGui::GetFrameHeight() * 2;
        ImGui::BeginChild(ImGui::GetID(GetName()), ImVec2(ImGui::GetWindowSize().x, child_height), true);
        // ImGui::TextUnformatted("THIS IS SOME PLACEHOLDER TEXT -- ADD TOOLS HERE FOR SELECTING TILE SETS");
        std::string name = "";
        if (mpSelectedTileSet)
        {
            name = mpSelectedTileSet->GetFileLocation().filename().string();
        }
        if (ImGui::BeginCombo("Tile Sets", name.c_str()))
        {
            for (auto iter = mTileSets.begin(); iter != mTileSets.end(); iter++)
            {
                bool selected = false;
                if (ImGui::Selectable(iter->second->GetFileLocation().filename().string().c_str(), &selected))
                {
                    ImGui::SetItemDefaultFocus();
                    mpSelectedTileSet = iter->second;
                    Invalidate();
                }
            }

            ImGui::EndCombo();
        }
        

        ImGui::EndChild();

        mWorkAreaPos = { ImGui::GetWindowPos().x, ImGui::GetWindowPos().y };
        mWorkAreaSize = { ImGui::GetWindowSize().x, ImGui::GetWindowSize().y };
        mScrollOffset = { ImGui::GetScrollX(), ImGui::GetScrollY() };

        // Adjust pos and size to account for the title bar
        mWorkAreaPos.Y += ImGui::GetFrameHeight();
        mWorkAreaSize.Y -= ImGui::GetFrameHeight();

        // Adjust for tool bar
        mWorkAreaPos.Y += child_height;
        mWorkAreaSize.Y -= child_height;
        
        if (mpViewImage)
        {
            ImGui::Image((ImTextureID)mpViewImage->GetGLTextureID64(), 
                        ImVec2(mpViewImage->GetWidth(), mpViewImage->GetHeight()), ImVec2(0, 1), ImVec2(1, 0)); // the last 2 params are flipping the image on the y
        }

        ImGui::End();
        return mIsOpen;
    }

    void TileSetView::ClearTileSets()
    {
        mTileSets.clear();
        mpSelectedTileSet = nullptr;
        mSelectedTile = {-1, -1};
        Invalidate(true);
    }

    void TileSetView::AddTileSet(TileSet* set)
    {
        mTileSets[set->GetTileSetID()] = set;

        if (!mpSelectedTileSet)
        {
            mpSelectedTileSet = set;
            Invalidate(true);
        }
    }

    TileSet* TileSetView::GetTileSet()
    {
        return mpSelectedTileSet;   
    }

    
    Vec2i TileSetView::GetSelectedTile()
    {
        return mSelectedTile;
    }

    void TileSetView::Invalidate(bool remake_frame_buffer)
    {
        mInvalidate = true;
        if (remake_frame_buffer && mFrameBuffer != -1)
        {
            Core::Graphics().DestroyRenderTexture(mFrameBuffer);
            mFrameBuffer = -1;
        }
    }
}}