/******************************************************************************
*	File		-	imgui_ext.cpp
*	Author		-	Joey Pollack
*	Date		-	2022/07/07 (y/m/d)
*	Mod Date	-	2022/07/07 (y/m/d)
*	Description	-	Adds new and custom methods to the imgui api
******************************************************************************/

#include "imgui_ext.h"

#include <dearimgui/imgui.h>
#include <dearimgui/imgui_internal.h>

namespace lunarium
{
    /// This function was taken from the Hazel engine written by Cherno!
    /// https://github.com/TheCherno/Hazel/blob/master/Hazelnut/src/Panels/SceneHierarchyPanel.cpp
    bool ImGuiExt::Vec3Control(const std::string& label, glm::vec3& values, float resetValue, float columnWidth)
    {
		bool values_updated = false;
		ImGui::PushID(label.c_str());

		ImGui::Columns(2);
		ImGui::SetColumnWidth(0, columnWidth);
		ImGui::Text(label.c_str());
		ImGui::NextColumn();

		ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
		ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2{ 0, 0 });

		float lineHeight = GImGui->Font->FontSize + GImGui->Style.FramePadding.y * 2.0f;
		ImVec2 buttonSize = { lineHeight + 3.0f, lineHeight };

		ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.8f, 0.1f, 0.15f, 1.0f });
		ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{ 0.9f, 0.2f, 0.2f, 1.0f });
		ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.8f, 0.1f, 0.15f, 1.0f });
		//ImGui::PushFont(boldFont);
		if (ImGui::Button("X", buttonSize))
			values.x = resetValue;
		//ImGui::PopFont();
		ImGui::PopStyleColor(3);

		ImGui::SameLine();
		values_updated = ImGui::DragFloat("##X", &values.x, 0.1f, 0.0f, 0.0f, "%.2f") | values_updated;
		ImGui::PopItemWidth();
		ImGui::SameLine();

		ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.2f, 0.7f, 0.2f, 1.0f });
		ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{ 0.3f, 0.8f, 0.3f, 1.0f });
		ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.2f, 0.7f, 0.2f, 1.0f });
		//ImGui::PushFont(boldFont);
		if (ImGui::Button("Y", buttonSize))
			values.y = resetValue;
		//ImGui::PopFont();
		ImGui::PopStyleColor(3);

		ImGui::SameLine();
		values_updated = ImGui::DragFloat("##Y", &values.y, 0.1f, 0.0f, 0.0f, "%.2f") | values_updated;
		ImGui::PopItemWidth();
		ImGui::SameLine();

		ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.1f, 0.25f, 0.8f, 1.0f });
		ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{ 0.2f, 0.35f, 0.9f, 1.0f });
		ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.1f, 0.25f, 0.8f, 1.0f });
		//ImGui::PushFont(boldFont);
		if (ImGui::Button("Z", buttonSize))
			values.z = resetValue;
		//ImGui::PopFont();
		ImGui::PopStyleColor(3);

		ImGui::SameLine();
		values_updated = ImGui::DragFloat("##Z", &values.z, 0.1f, 0.0f, 0.0f, "%.2f") | values_updated;
		ImGui::PopItemWidth();

		ImGui::PopStyleVar();

		ImGui::Columns(1);

		ImGui::PopID();

		return values_updated;
    }

	bool ImGuiExt::Vec2Control(const std::string& label, glm::vec2& values, float resetValue, float columnWidth)
	{
		glm::vec3 temp = { values.x, values.y, 0.0 };
		bool result = Vec2Control(label, temp, resetValue, columnWidth);
		values.x = temp.x;
		values.y = temp.y;
		return result;
	}

	
	bool ImGuiExt::Vec2Control(const std::string& label, glm::vec3& values, float resetValue, float columnWidth)
	{
		bool values_updated = false;
		ImGui::PushID(label.c_str());

		ImGui::Columns(2);
		ImGui::SetColumnWidth(0, columnWidth);
		ImGui::Text(label.c_str());
		ImGui::NextColumn();

		ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
		ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2{ 0, 0 });

		float lineHeight = GImGui->Font->FontSize + GImGui->Style.FramePadding.y * 2.0f;
		ImVec2 buttonSize = { lineHeight + 3.0f, lineHeight };

		ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.8f, 0.1f, 0.15f, 1.0f });
		ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{ 0.9f, 0.2f, 0.2f, 1.0f });
		ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.8f, 0.1f, 0.15f, 1.0f });
		//ImGui::PushFont(boldFont);
		if (ImGui::Button("X", buttonSize))
			values.x = resetValue;
		//ImGui::PopFont();
		ImGui::PopStyleColor(3);

		ImGui::SameLine();
		values_updated = ImGui::DragFloat("##X", &values.x, 0.1f, 0.0f, 0.0f, "%.2f") | values_updated;
		ImGui::PopItemWidth();
		ImGui::SameLine();

		ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.2f, 0.7f, 0.2f, 1.0f });
		ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{ 0.3f, 0.8f, 0.3f, 1.0f });
		ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.2f, 0.7f, 0.2f, 1.0f });
		//ImGui::PushFont(boldFont);
		if (ImGui::Button("Y", buttonSize))
			values.y = resetValue;
		//ImGui::PopFont();
		ImGui::PopStyleColor(3);

		ImGui::SameLine();
		values_updated = ImGui::DragFloat("##Y", &values.y, 0.1f, 0.0f, 0.0f, "%.2f") | values_updated;
		ImGui::PopItemWidth();

		ImGui::PopStyleVar();

		ImGui::Columns(1);

		ImGui::PopID();

		return values_updated;
	}

	
	bool ImGuiExt::FloatControl(const std::string& label, float& value, float resetValue, float columnWidth)
	{
		bool values_updated = false;
		ImGui::PushID(label.c_str());

		ImGui::Columns(2);
		ImGui::SetColumnWidth(0, columnWidth);
		ImGui::Text(label.c_str());
		ImGui::NextColumn();

		ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
		ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2{ 0, 0 });

		float lineHeight = GImGui->Font->FontSize + GImGui->Style.FramePadding.y * 2.0f;
		ImVec2 buttonSize = { lineHeight + 3.0f, lineHeight };

		ImGui::PushStyleColor(ImGuiCol_Button, ImVec4{ 0.8f, 0.1f, 0.15f, 1.0f });
		ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4{ 0.9f, 0.2f, 0.2f, 1.0f });
		ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.8f, 0.1f, 0.15f, 1.0f });
		//ImGui::PushFont(boldFont);
		if (ImGui::Button("R", buttonSize))
			value = resetValue;
		//ImGui::PopFont();
		ImGui::PopStyleColor(3);

		ImGui::SameLine();
		values_updated = ImGui::DragFloat("##X", &value, 0.1f, 0.0f, 0.0f, "%.2f");
		ImGui::PopItemWidth();

		
		ImGui::PopStyleVar();

		ImGui::Columns(1);

		ImGui::PopID();
		return values_updated;
	}
    
    /// Only works if this is the only item on the line
    void ImGuiExt::TextCentered(const std::string text)
    {
        auto windowWidth = ImGui::GetWindowSize().x;
        auto textWidth   = ImGui::CalcTextSize(text.c_str()).x;

        ImGui::SetCursorPosX((windowWidth - textWidth) * 0.5f);
        ImGui::Text(text.c_str());
    }

    // Not recommended but the only way to do it for now
    // https://github.com/ocornut/imgui/discussions/3862
    bool ImGuiExt::ButtonCentered(const char* label, float alignment)
    {
        ImGuiStyle& style = ImGui::GetStyle();

        float size = ImGui::CalcTextSize(label).x + style.FramePadding.x * 2.0f;
        float avail = ImGui::GetContentRegionAvail().x;

        float off = (avail - size) * alignment;
        if (off > 0.0f)
            ImGui::SetCursorPosX(ImGui::GetCursorPosX() + off);

        return ImGui::Button(label);
    }

	bool ImGuiExt::CheckBoxLeft(const char* label, bool* v)
	{
		ImGui::Text(label);
		ImGui::SameLine();
		std::string lb = "##";
		lb.append(label);
		return ImGui::Checkbox(lb.c_str(), v);
	}
}