/******************************************************************************
*	File		-	map_canvas.cpp
*	Author		-	Joey Pollack
*	Date		-	2022/02/14 (y/m/d)
*	Mod Date	-	2022/02/14 (y/m/d)
*	Description	-	the canvas panel for painting map tiles
******************************************************************************/

#include "map_canvas.h"
#include "../map_editor.h"
#include <editor/editor.h>
#include <editor/contents/tile_map.h>
#include <dearimgui/imgui.h>
#include <core/core.h>
#include <graphics/graphics.h>
#include <assets/types/image.h>

#include <string>
#include <sstream>

namespace lunarium { namespace editor 
{
    MapCanvas::MapCanvas(MapEditor* editor)
        : Panel("Map Canvas", gui::PanelDockZone::DDZ_CENTER, true),
        mpMapEditor(editor), mpCanvasImage(nullptr), mMap(nullptr), mSelectedTile({-1, -1}), mFrameBuffer(-1), mMapSizeChanged(false),
        mZoomFactor(1.0f), mScrollDragged(false), mCurrentRegion({0, 0}), mRegionString("")
    {
        mRegionString = std::to_string(mCurrentRegion.X);
        mRegionString += ",";
        mRegionString += std::to_string(mCurrentRegion.Y);
    }

    void MapCanvas::Update(float delta)
    {   
        // Get mouse coords
        float x = ImGui::GetMousePos().x;
        float y = ImGui::GetMousePos().y;

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


        // Check that mouse pos is within the window
        bool is_in_window = x >= 0.0f && x < mWorkAreaSize.X && y >= 0.0f && y < mWorkAreaSize.Y;

        // Adjust for scrolling
        x += mScrollOffset.X;
        y += mScrollOffset.Y;
        
        // Do zooming
        float wheel = ImGui::GetIO().MouseWheel;
        if (!(wheel < 0.1f && wheel > -0.1f) && is_in_window)
        {
            if (ImGui::GetIO().KeyCtrl)
            {
                mZoomFactor += wheel * 0.05f;
                mpCanvasImage = nullptr;
            }
        }

        // Do middle mouse scrolling
        if (ImGui::IsMouseDown(ImGuiMouseButton_Middle))
        {
            mScrollOffset.X -= ImGui::GetIO().MouseDelta.x;
            if (mScrollOffset.X < 0.0f)
            {
                mScrollOffset.X = 0.0f;
            }
            

            mScrollOffset.Y -= ImGui::GetIO().MouseDelta.y;
            if (mScrollOffset.Y < 0.0f)
            {
                mScrollOffset.Y = 0.0f;
            }

            mScrollDragged = true;
        }
        else
        {
            mScrollDragged = false;
        }

        // Check for input and update map
        if (mMap && ImGui::GetIO().MouseDown[ImGuiMouseButton_Left] && mSelectedTile.TileSetID > -1 
                && mSelectedTile.TileIndex.X > -1&& mSelectedTile.TileIndex.Y > -1)
        {

            if (is_in_window)
            {
                // Convert to tile grid index
                x /= (mMap->GetTileSize().Width * mZoomFactor);
                y /= (mMap->GetTileSize().Height * mZoomFactor);

                // Don't update the map if the current tile is already set to the selected tile
                if (mMap->GetTile({ (int)x, (int)y }) != mSelectedTile)
                {
                    mMap->SetTile(mSelectedTile, { (int)x, (int)y });
                    mpCanvasImage = nullptr;
                }
            }
        }

        // Check if redraw is needed
        if (!mpCanvasImage)
        {
            if (mMap)
            {
                if (mMapSizeChanged)
                {
                    Core::Graphics().DestroyRenderTexture(mFrameBuffer);
                    mFrameBuffer = -1;
                    mMapSizeChanged = false;
                }

                if (mFrameBuffer == -1)
                {
                    mFrameBuffer = Core::Graphics().CreateRenderTexture(mMap->GetSizeInPixels().Width, mMap->GetSizeInPixels().Height, 4);
                }

                Color prev = Core::Graphics().GetClearColor();
                Core::Graphics().SetClearColor(Color::Transparent());
                Core::GetInstance().BeginRenderToTexture(mFrameBuffer).LogIfFailed(Editor::LogCat);
                mMap->Render(&Core::Graphics());
                mpCanvasImage = Core::GetInstance().EndRenderToTexture();
                Core::Graphics().SetClearColor(prev);
            }
        }
    }

    bool MapCanvas::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_NoScrollbar))
        {
            ImGui::PopStyleVar(3);
            ImGui::End();
            return false;
        }

        ImGui::PopStyleVar(3);

        ImVec2 pos = ImGui::GetWindowPos();
        ImVec2 size = ImGui::GetWindowSize();

        float child_height = ImGui::GetFrameHeight() * 2;
        ImGui::BeginChild("Map Tool Bar", ImVec2(ImGui::GetWindowSize().x, child_height), true);

        // tool bar
        DoToolBar();

        ImGui::EndChild();

        ImGui::BeginChild("Map Canvas", ImVec2(ImGui::GetWindowSize().x, ImGui::GetWindowSize().y - child_height), true);

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

        if (mScrollDragged)
        {
            ImGui::SetScrollX(mScrollOffset.X);
            ImGui::SetScrollY(mScrollOffset.Y);
            mScrollDragged = false;
        }
        else
        {
            mScrollOffset = { ImGui::GetScrollX(), ImGui::GetScrollY() };
        }

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

        // // Adjust y pos and size to account for the tool bar
        // mWorkAreaPos.Y += child_height;
        // mWorkAreaSize.Y -= child_height;

        //ImGui::Text(mMouseStatusInfo.c_str());
        if (mpCanvasImage)
        {
            ImGui::Image((ImTextureID)mpCanvasImage->GetGLTextureID64(), 
                        ImVec2(mpCanvasImage->GetWidth() * mZoomFactor, mpCanvasImage->GetHeight() * mZoomFactor), ImVec2(0, 1), ImVec2(1, 0));
        }

        ImGui::EndChild();
        ImGui::End();
        return mIsOpen;
    }

    void MapCanvas::SetTileMap(TileMap* pMap)
    {   
        if (mMap && mMap->GetSizeInPixels() != pMap->GetSizeInPixels())
        {
            mMapSizeChanged = true;
        }

        mMap = pMap;

        // Force the image to redraw
        mpCanvasImage = nullptr;
    }

    void MapCanvas::SetSelectedTile(TileRef tile)
    {
        mSelectedTile = tile;
    }
    
    TileRef MapCanvas::GetSelectedTile() const
    {
        return mSelectedTile;
    }

    void MapCanvas::MapSizeChanged()
    {
        mMapSizeChanged = true;
        mpCanvasImage = nullptr;
    }

    ////////////////////////////////////////////////////////////
    //				RENDER HELPERS
    ////////////////////////////////////////////////////////////
    void MapCanvas::DoToolBar()
    {
        if (ImGui::BeginTable("tool bar", 2, ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_SizingFixedFit))
        {
            ImGui::AlignTextToFramePadding();
            ImGui::TableNextColumn();
            ImGui::Text("Zoom: ");
            ImGui::SameLine();
            ImGui::PushItemWidth(100.0f);
            ImGui::InputFloat("##zoom_factor", &mZoomFactor, 0.05f, 0.1f, "%.2f");     
            ImGui::PopItemWidth();
       
            // Region Selecting
            ImGui::TableNextColumn();   
            ImGui::Text("Regions: ");
            ImGui::SameLine(); 
            if (ImGui::Button("<="))
            {
                // TODO: Move to the next region to the left
            }

            if (ImGui::IsItemHovered())
                ImGui::SetTooltip("Move to the west");

            ImGui::SameLine();
            if (ImGui::Button("^"))
            {
                // TODO: Move to the next region to the north
            }

            if (ImGui::IsItemHovered())
                ImGui::SetTooltip("Move to the north");
            

            ImGui::SameLine();
            if (ImGui::Button("V"))
            {
                // TODO: Move to the next region to the south
            }

            if (ImGui::IsItemHovered())
                ImGui::SetTooltip("Move to the south");

            ImGui::SameLine();
            if (ImGui::Button("=>"))
            {
                // TODO: Move to the next region to the right
            }

            if (ImGui::IsItemHovered())
                ImGui::SetTooltip("Move to the east");

            ImGui::SameLine();
            ImGui::Text("Current: ");
            ImGui::SameLine();
            ImGui::PushItemWidth(50.0f);
            if (ImGui::InputText("##current_region", mRegionString.data(), mRegionString.size() + 1, ImGuiInputTextFlags_EnterReturnsTrue) 
                                    && mRegionString.size() > 2)
            {
                int x = -1, y = -1;
                if (std::isdigit(mRegionString[0]))
                {
                    x = std::atoi(&mRegionString[0]);

                    if (std::isdigit(mRegionString[2]))
                    {
                        mCurrentRegion.X = x;
                        mCurrentRegion.Y = std::atoi(&mRegionString[2]);
                    }
                }
            }  
            ImGui::PopItemWidth();
            
            // ImGui::TableNextColumn();
            // ImGui::Text("Status Bar");
            ImGui::EndTable();
        }
    }
     
}}