text: #pragma once
  
  #include "Panel.h"
  
  #include "Raybyte/Utils/Hash.h"
  
  #include <unordered_map>
  
  namespace Raybyte {
  
  	struct PanelData
  	{
  		uint32 Hash = 0;
  		const char* Name = "";
  		Ref<Panel> Panel = nullptr;
  		bool IsOpen = false;
  	};
  
  	class PanelManager
  	{
  	public:
  		PanelManager() = default;
  		~PanelManager()
  		{
  			m_Panels.clear();
  		}
  
  		void OnGUI()
  		{
  			RB_FUNCTION();
  
  			for (auto& [hash, data] : m_Panels)
  			{
  				if (!data.IsOpen)
  				{
  					data.Panel->m_Info.ContentRegionAvail = { 0.0f, 0.0f };
  					data.Panel->m_Info.Size = { 0.0f, 0.0f };
  					data.Panel->m_Info.Position = { 0.0f, 0.0f };
  					data.Panel->m_Info.Focused = false;
  					data.Panel->m_Info.Hovered = false;
  					data.Panel->m_Info.MouseHoveringRect = false;
  					data.Panel->m_Info.Visible = false;
  					continue;
  				}
  
  				ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { data.Panel->m_Settings.Padding.x, data.Panel->m_Settings.Padding.y });
  				ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { data.Panel->m_Settings.ItemSpacing.x, data.Panel->m_Settings.ItemSpacing.y });
  
  				ImGuiWindowFlags flags = 0;
  				if (data.Panel->m_Settings.NoDecoration)
  					flags |= ImGuiWindowFlags_NoDecoration;
  				if (data.Panel->m_Settings.NoScrollbar)
  					flags |= ImGuiWindowFlags_NoScrollbar;
  				if (data.Panel->m_Settings.NoScrollWithMouse)
  					flags |= ImGuiWindowFlags_NoScrollWithMouse;
  
  				ImGui::Begin(data.Name, &data.IsOpen, flags);
  
  				ImGui::PushID(data.Hash);
  
  				ImVec2 minRegion = ImGui::GetWindowContentRegionMin();
  				ImVec2 maxRegion = ImGui::GetWindowContentRegionMax();
  				ImVec2 windowPos = ImGui::GetWindowPos();
  				data.Panel->m_Info.Bounds[0] = { minRegion.x + windowPos.x, minRegion.y + windowPos.y };
  				data.Panel->m_Info.Bounds[1] = { maxRegion.x + windowPos.x, maxRegion.y + windowPos.y };
  
  				data.Panel->m_Info.ContentRegionAvail = { ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y };
  				data.Panel->m_Info.Size = { ImGui::GetWindowSize().x, ImGui::GetWindowSize().y };
  				data.Panel->m_Info.Position = { ImGui::GetWindowPos().x, ImGui::GetWindowPos().y };
  				data.Panel->m_Info.Focused = ImGui::IsWindowFocused();
  				data.Panel->m_Info.Hovered = ImGui::IsWindowHovered();
  				data.Panel->m_Info.MouseHoveringRect = ImGui::IsMouseHoveringRect({ data.Panel->m_Info.Bounds[0].x, data.Panel->m_Info.Bounds[0].y }, { data.Panel->m_Info.Bounds[1].x, data.Panel->m_Info.Bounds[1].y });
  				data.Panel->m_Info.Visible = true;
  
  				data.Panel->OnGUI();
  
  				ImGui::PopID();
  
  				ImGui::End();
  				ImGui::PopStyleVar(2);
  			}
  		}
  
  		void OnEvent(Event& event)
  		{
  			for (auto& [hash, data] : m_Panels)
  				data.Panel->OnEvent(event);
  		}
  
  		template<typename TPanel, typename... TArgs>
  		Ref<TPanel> AddPanel(const char* stringID, const char* name, TArgs&&... args)
  		{
  			RB_FUNCTION();
  
  			static_assert(std::is_base_of<Panel, TPanel>::value);
  
  			Ref<TPanel> panel = Ref<TPanel>::Create(std::forward<TArgs>(args)...);
  			uint32 hash = Hash::FNV(stringID);
  
  			PanelData data;
  			data.Hash = hash;
  			data.Name = name;
  			data.Panel = panel;
  			data.IsOpen = true;
  
  			m_Panels[hash] = data;
  			return panel;
  		}
  		
  		template<typename TPanel>
  		Ref<TPanel> GetPanel(const char* stringID)
  		{
  			static_assert(std::is_base_of<Panel, TPanel>::value);
  			uint32 hash = Hash::FNV(stringID);
  			return m_Panels[hash].Panel.As<TPanel>();
  		}
  
  		void OpenPanel(const char* stringID) { m_Panels[Hash::FNV(stringID)].IsOpen = true; }
  		void ClosePanel(const char* stringID) { m_Panels[Hash::FNV(stringID)].IsOpen = false; }
  	private:
  		std::unordered_map<uint32, PanelData> m_Panels;
  	};
  
  }