text: #pragma once
  
  #include "ApplicationState.h"
  #include "Constants.h"
  #include "PointerWrappers.h"
  #include "Window/Window.h"
  
  #include "Events/Event.h"
  #include "Events/WindowEvent.h"
  
  #include "Raybyte/Graphics/API/ImGuiRenderer.h"
  
  #include <glm/glm.hpp>
  
  namespace Raybyte {
  
  	struct ApplicationConfig
  	{
  		uint32 WindowWidth = 1280;
  		uint32 WindowHeight = 720;
  		std::string WindowTitle = "Raybyte App";
  		glm::vec4 BackgroundColor = {};
  		bool Multithread = false;
  		bool Fullscreen = false;
  		bool MaximizeOnStart = false;
  		bool VSync = true;
  		bool EnableImGui = true;
  		bool DockingEnable = true;
  	};
  	
  	class ApplicationContext
  	{
  	public:
  		ApplicationContext(const ApplicationConfig& config);
  		virtual ~ApplicationContext();
  
  		void Run();
  		void UpdateAndRenderThread(bool pollEvents);
  		void Close();
  		void Shutdown();
  
  		virtual void OnStart() {}
  
  		uint32 GetFPS() const { return m_FPS; }
  
  		Ref<Window> GetWindow() const { return m_Window; }
  		Ref<ImGuiRenderer> GetImGuiRenderer() const { return m_ImGuiRenderer; }
  
  		static ApplicationContext* GetInstance() { return s_Instance; }
  
  		static const char* GetConfigurationName();
  		static const char* GetOSName();
  	protected:
  		void AddState(ApplicationState* state);
  	private:
  		void DispatchEvents(Event& event);
  		bool OnWindowClose(WindowCloseEvent& e);
  		bool OnWindowResize(WindowResizeEvent& e);
  	private:
  		static ApplicationContext* s_Instance;
  
  		Ref<Window> m_Window;
  		Ref<ImGuiRenderer> m_ImGuiRenderer;
  
  		std::vector<ApplicationState*> m_States;
  
  		glm::vec4 m_SwapchainClearColor = {};
  		
  		std::atomic<bool> m_Running = true;
  		std::atomic<bool> m_Minimized = false;
  		bool m_Multithread = false;
  		bool m_DockingEnable = false;
  
  		uint32 m_Frames = 0;
  		uint32 m_FPS = 0;
  		float m_LastFrameTime = 0.0f;
  
  		float m_StateUpdateTime = 0.0f;
  		float m_ImGuiRenderTime = 0.0f;
  		float m_CmdQueueExecTime = 0.0f;
  		float m_SwapBuffersTime = 0.0f;
  	};
  
  	ApplicationContext* CreateContext();
  
  }