#include "CoreHandler.h"
#include <sstream>
#include "imgui/imgui.h"
#include "imgui/imgui_impl_dx11.h"
#include "imgui/imgui_impl_win32.h"

using namespace std;

CoreHandler::CoreHandler(Window& window, Logger& logger)
{
	// init local variable
	seed = 0.0f;
	seed = int(seed) % 10000;
};

void CoreHandler::InitCoreHandler(Window& window, Logger& logger)
{
    // init imgui
    ImGui_ImplDX11_Init(window.GetGfx().getDevice().Get(), window.GetGfx().getContext().Get());
}

void CoreHandler::CloseCoreHandler()
{
    // close imgui
    ImGui_ImplDX11_Shutdown();
}

void CoreHandler::processEvents(Window& window, Graphics& gfx, HWND& hWnd, Logger& logger)
{
    // Process event
    while (!Window::mouse.IsQueueEmpty())
    {
        auto mouseEvent = Window::mouse.ReadEvent();
        switch (mouseEvent.GetType())
        {
        case (Mouse::MouseEvent::Type::Move):
        {
            std::ostringstream oss;
            oss << "(" << mouseEvent.GetX() << "," << mouseEvent.GetY() << "): Mouse Moved";

            // Check if drag by right button
            if (Window::mouse.IsRightClicked())
            {
                cameraDeltaX = Window::mouse.GetRightDragDeltaX();
                cameraDeltaY = Window::mouse.GetRightDragDeltaY();

                if (cameraY + cameraDeltaY >= 80)
                {
                    cameraDeltaY = 80 - cameraY;
                }
                if (cameraY + cameraDeltaY <= 40)
                {
                    cameraDeltaY = 40 - cameraY;
                }
            }
            oss << " | ViewAt(" << cameraX << "," << cameraY << ")";
            oss << " | Dragging(" << cameraDeltaX << "," << cameraDeltaY << ")";
            oss << " | vSinValue(" << sin((cameraY + cameraDeltaY) / 100.0f) << ")";

            //window.SetTitle(hWnd, oss.str());
            break;
        }
        case (Mouse::MouseEvent::Type::LClick):
        {
            std::ostringstream oss;
            oss << "(" << mouseEvent.GetX() << "," << mouseEvent.GetY() << "): Mouse Left Clicked";
            //window.SetTitle(hWnd, oss.str());
            break;
        }
        case (Mouse::MouseEvent::Type::LRelease):
        {
            std::ostringstream oss;
            oss << "(" << mouseEvent.GetX() << "," << mouseEvent.GetY() << "): Mouse Left Released";
            //window.SetTitle(hWnd, oss.str());
            break;
        }
        case (Mouse::MouseEvent::Type::RClick):
        {
            std::ostringstream oss;
            oss << "(" << mouseEvent.GetX() << "," << mouseEvent.GetY() << "): Mouse Right Clicked";
            //window.SetTitle(hWnd, oss.str());
            break;
        }
        case (Mouse::MouseEvent::Type::RRelease):
        {
            std::ostringstream oss;

            cameraX += cameraDeltaX;
            cameraY += cameraDeltaY;

            cameraDeltaX = 0;
            cameraDeltaY = 0;

            oss << "(" << mouseEvent.GetX() << "," << mouseEvent.GetY() << "): Mouse Right Released";
            //window.SetTitle(hWnd, oss.str());
            break;
        }
        case (Mouse::MouseEvent::Type::Wheel):
        {
            std::ostringstream oss;

            cameraDeltaZ = Window::mouse.GetWheelDelta();

            oss << "(" << mouseEvent.GetX() << "," << mouseEvent.GetY() << "): Mouse WheelUp";
            oss << " | cameraDeltaZ(" << cameraDeltaZ << ")";

            //window.SetTitle(hWnd, oss.str());
            break;
        }
        }
    }
}

void CoreHandler::CoreProcess(Window& window, Graphics& gfx, HWND& hWnd, Logger& logger)
{
    // render imgui
    ImGui_ImplDX11_NewFrame();
    ImGui_ImplWin32_NewFrame();
    ImGui::NewFrame();

    // Process IO events
    processEvents(window, gfx, hWnd, logger);
 
    // Display background and set depthstencil
    window.GetGfx().RendorFrame();

    // Set camera
    SetCamera(window, logger);

    // Draw all scenes
    window.DrawScenes(window.GetGfx(), logger);

    // render imgui
    auto imIO = ImGui::GetIO();
    //ImGui::Text("camera Y       : [ %.2f ]", cameraY);
    //ImGui::Text("camera Delta Y : [ %.2f ]", cameraDeltaY);
    //ImGui::Text("wheelDelta     : [ %d ]", window.mouse.GetWheelDelta());
    ImGui::Text("Framerate      : [ %.2f ]", imIO.Framerate);
    ImGui::Text("MS per Frame   : [ %.3f ]", 1000.0f / imIO.Framerate);
    ImGui::Render();
    ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());

    // Set view port and present
    window.GetGfx().EndFrame();
};

void CoreHandler::SetCamera(Window& window, Logger& logger)
{
    // Put camera calculation logic here
    /*seed++;
    auto dt = sin(seed / 1000);
    logger.PutLog("seed", std::to_string(seed));
    logger.PutLog("dt", std::to_string(dt));

    auto sinValue = sin(seed / 5000);
    auto cosValue = cos(seed / 5000);

    // Set camera
    DirectX::XMVECTOR eyePosition = DirectX::XMVectorSet(5.0f * sinValue, 3.0f, -5.0f * cosValue, 1.0f);
    DirectX::XMVECTOR focusPosition = DirectX::XMVectorZero();
    DirectX::XMVECTOR upDirection = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 1.0f);*/

    float radius = cameraZ - cameraDeltaZ / 120.0f;

    auto vSinValue = sin((cameraY + cameraDeltaY) / 100.0f);
    auto vCosValue = cos((cameraY + cameraDeltaY) / 100.0f);
    
    float eyePosY = radius * vSinValue;
    float hRadius = radius * vCosValue; // horizon radius

    auto sinValue = sin((cameraX + cameraDeltaX) / 100.0f);
    auto cosValue = cos((cameraX + cameraDeltaX) / 100.0f);

    DirectX::XMVECTOR eyePosition = DirectX::XMVectorSet(-hRadius * sinValue, eyePosY, hRadius * cosValue, 1.0f);
    DirectX::XMVECTOR focusPosition = DirectX::XMVectorZero();
    DirectX::XMVECTOR upDirection = DirectX::XMVectorSet(0.0f, 1.0f, 0.0f, 1.0f);

    window.GetGfx().SetCamera(logger, eyePosition, focusPosition, upDirection);
}