/******************************************************************************
*	File		-	worldView.cpp
*	Author		-	Joey Pollack
*	Date		-	2022/01/26 (y/m/d)
*	Mod Date	-	2022/01/26 (y/m/d)
*	Description	-	A rendered view of the world
******************************************************************************/

#include "world_view.h"
#include <core/core.h>
#include <renderer/renderer2D.h>
#include <renderer/frame_buffer.h>
#include <renderer/texture.h>
#include <renderer/orthographic_camera.h>
#include <utils/logger.h>
#include <world/world.h>
#include <dearimgui/imgui.h>
#include <editor/editor.h>
#include <gui/panel_manager.h>
#include <internal_data/data_manager.h>

namespace lunarium { namespace editor
{
    WorldView::WorldView(Editor* pEditor)
        : Panel("World View", PanelDockZone::DDZ_CENTER, true, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar), mpWorld(nullptr),
            mFrameBuffer(nullptr), mWidth(0), mHeight(0), mNewViewSize(false), mIsWindowHovered(false), mpCanvasImage(nullptr), mEditorCamera(nullptr),
            mSimRunning(false), mpEditor(pEditor), mSimPaused(false)
    {

    }

    void WorldView::SetWorld(lunarium::World* pWorld)
    {
        mpWorld = pWorld;
    }

    lunarium::World* WorldView::GetWorld()
    {
        return mpWorld;
    }

    void WorldView::Update(float delta)
    {
        // Need to remake the frame buffer if the window size has changed
        if (mNewViewSize)
        {
            mNewViewSize = false;

            if (mFrameBuffer)
            {
                FrameBuffer::Destroy(&mFrameBuffer);
            }

            mFrameBuffer = FrameBuffer::Create(mWidth, mHeight);
            Vec2f pos = (mEditorCamera ? mEditorCamera->GetPosition() : Vec2f {0.0f, 0.0f});
            delete mEditorCamera;
            mEditorCamera = new OrthographicCamera(pos, { (float)mWidth, (float)mHeight });
        }

        // Handle view navigation input
        if (ImGui::IsMouseDown(ImGuiMouseButton_Middle) && mIsWindowHovered)
        {

            mEditorCamera->MoveLeft(-ImGui::GetIO().MouseDelta.x);
            mEditorCamera->MoveUp(-ImGui::GetIO().MouseDelta.y);
        }

        if (mSimRunning && !mSimPaused && mpWorld)
        {
            mpWorld->Update(delta);
        }

        // Render the current state of the world
        if (mpWorld && mFrameBuffer)
        {
            mFrameBuffer->Bind();
            Core::Graphics().BeginDraw(mEditorCamera);
            mpWorld->Render(&Core::Graphics());
            Core::Graphics().EndDraw();
            mFrameBuffer->Unbind();
            mpCanvasImage = mFrameBuffer->GetTexture();
        }
    }

    void WorldView::DoFrame()
    { 
        // TODO: Draw toolbar
        ImVec2 window_size = ImGui::GetWindowSize();

        float child_height = ImGui::GetFrameHeight() * 2.5;
        ImGui::BeginChild("World View Toolbar", ImVec2(ImGui::GetContentRegionAvailWidth(), child_height), true);
        DoToolBar();
        ImGui::EndChild();
        ImGui::BeginChild("World View", ImVec2(ImGui::GetContentRegionAvailWidth(), ImGui::GetWindowSize().y - child_height), true);
        
        if (mWidth != ImGui::GetWindowSize().x || mHeight != ImGui::GetWindowSize().y)
        {
            mWidth = ImGui::GetWindowSize().x;
            mHeight = ImGui::GetWindowSize().y;
            mNewViewSize = true;
        }

        mIsWindowHovered = ImGui::IsWindowHovered();

        // Draw world render
        if (mpCanvasImage)
        {
            ImGui::Image((ImTextureID)mpCanvasImage->GetGLID64(), 
                        ImVec2(mpCanvasImage->GetWidth(), mpCanvasImage->GetHeight()), ImVec2(0, 1), ImVec2(1, 0));
        }
        
        ImGui::EndChild();
    }

    
    void WorldView::DoToolBar()
    {
        ImVec4 tint = mSimRunning ? ImVec4(0.5f, 0.5f, 0.5f, 1.0f) : ImVec4(1, 1, 1, 1);
        ImGui::SetCursorPosX(ImGui::GetContentRegionAvailWidth() / 2 - 48);     // 48 is 32 + 16 which is 1 and a half button widths
        if (ImGui::ImageButton((ImTextureID)DataManager::mPlayArrow->GetGLID64(), 
            ImVec2(DataManager::mPlayArrow->GetWidth(), DataManager::mPlayArrow->GetHeight()), 
            ImVec2(0, 0), ImVec2(1, 1), -1, ImVec4(0, 0, 0, 0), tint) && !mSimRunning)
        {
            if (mSimPaused)
            {
                mSimPaused = false;
            }
            else
            {
                mpEditor->OnPlay();
                mWorldState = mpWorld->GetState();
                mpWorld->OnLoad();
                mSimRunning = true;
            }
        }

        ImGui::SameLine();
        tint = !mSimRunning ? ImVec4(0.5f, 0.5f, 0.5f, 1.0f) : ImVec4(1, 1, 1, 1);
        if (ImGui::ImageButton((ImTextureID)DataManager::mPause->GetGLID64(), 
            ImVec2(DataManager::mPause->GetWidth(), DataManager::mPause->GetHeight()), 
            ImVec2(0, 0), ImVec2(1, 1), -1, ImVec4(0, 0, 0, 0), tint))
        {
            mpEditor->OnPause();
            mSimPaused = !mSimPaused;
        }

        ImGui::SameLine();

        tint = !mSimRunning ? ImVec4(0.5f, 0.5f, 0.5f, 1.0f) : ImVec4(1, 1, 1, 1);
        if (ImGui::ImageButton((ImTextureID)DataManager::mStop->GetGLID64(), 
            ImVec2(DataManager::mStop->GetWidth(), DataManager::mStop->GetHeight()), 
            ImVec2(0, 0), ImVec2(1, 1), -1, ImVec4(0, 0, 0, 0), tint) && mSimRunning)
        {
            mpEditor->OnStop();
            mpWorld->OnUnload();
            mpWorld->ResetState(mWorldState);
            mSimRunning = false;
        }
    }
}}