#ifndef _HEADER_INPUT_MANAGER
#define _HEADER_INPUT_MANAGER

#include "InputDeviceBases.hpp"
#include "TeaCallback.hpp"
#include <map>
#include <string.h>
#include <vector>

namespace Input
{
	class InputManager
	{
	public:
		static bool IsInitialized();
		static bool Initialize();
		static void Cleanup();
		static InputManager* GetInstance();

	private:
		static bool s_isInitialized;
		static InputManager* s_instance;

	public:
		InputManager();
		~InputManager();

		InputDeviceType GetConnectedType()
		{
			if (joystick)
				return joystick->GetDeviceType();
			return IDT_NONE;
		}
		bool IsJoystickConnected(const unsigned int a_Channel);

		void SearchForJoystick();

		std::vector<std::wstring>& GetJoystickNames();
		void AddJoystickName(std::wstring a_name);

		void ConnectJoystickByIndex(size_t m_index);

		void Update();

		void RegisterCallback(InputJoystickPhysical a_Button, InputManagerEvent a_Event, void(*a_CallbackFunction)())
		{
			std::pair<InputJoystickPhysical, InputManagerEvent> newEvent(a_Button, a_Event);
			if (m_joystickCallbacks.find(newEvent) == m_joystickCallbacks.end())
			{
				m_joystickCallbacks[newEvent] = new TeaLib::Utility::Callback<>();
			}
			m_joystickCallbacks[newEvent]->Register(a_CallbackFunction);
		}
		template<typename ClassType> void RegisterCallback(InputJoystickPhysical a_Button, InputManagerEvent a_Event, ClassType* a_ClassInstance, void(ClassType::*a_CallbackFunction)())
		{
			std::pair<InputJoystickPhysical, InputManagerEvent> newEvent(a_Button, a_Event);
			if (m_joystickCallbacks.find(newEvent) == m_joystickCallbacks.end())
			{
				m_joystickCallbacks[newEvent] = new TeaLib::Utility::Callback<>();
			}
			m_joystickCallbacks[newEvent]->Register(a_ClassInstance, a_CallbackFunction);
		}
		void DeregisterCallback(InputJoystickPhysical a_Button, InputManagerEvent a_Event, void(*a_CallbackFunction)())
		{
			if (!this)
				return;
			std::pair<InputJoystickPhysical, InputManagerEvent> newEvent(a_Button, a_Event);
			if (m_joystickCallbacks.find(newEvent) != m_joystickCallbacks.end())
			{
				m_joystickCallbacks[newEvent]->Deregister(a_CallbackFunction);
			};
		}
		template<typename ClassType> void DeregisterCallback(InputJoystickPhysical a_Button, InputManagerEvent a_Event, ClassType* a_ClassInstance, void(ClassType::*a_CallbackFunction)())
		{
			if (!this)
				return;
			std::pair<InputJoystickPhysical, InputManagerEvent> newEvent(a_Button, a_Event);
			if (m_joystickCallbacks.find(newEvent) != m_joystickCallbacks.end())
			{
				m_joystickCallbacks[newEvent]->Deregister(a_ClassInstance, a_CallbackFunction);
			}
		}

		void ClearCallbacks();

		Keyboard* keyboard;
		Joystick* joystick;

	private:
		std::vector<std::wstring> m_joystickNames;
		std::map<std::pair<InputJoystickPhysical, InputManagerEvent>, TeaLib::Utility::Callback<>*> m_joystickCallbacks;
	};
}

#endif
