#include "UnrealProject.h"
#if PLATFORM_SPECIFIC_WIN == 0

#define _SOURCE_INPUT_MANAGER
#include "InputManager.hpp"

#include "AllowWindowsPlatformTypes.h"

#pragma comment(lib, "dinput8.lib")
#pragma comment (lib, "dxguid.lib")

#define DIRECTINPUT_VERSION 0x0800
#include <Windows.h>

#include <dinput.h>
#include <map>

using namespace std;

#define DUALSHOCK4PRODUCTDATA	(0x05C4054CUL)
#define DUALSHOCK4DEVTYPE		(0x00010318UL)
#define WIREDXBOXDEVTYPE		(0x00010215UL)
#define PI						3.14159265359f

namespace Input
{
	struct GUID_Impl
	{
		GUID instance;
		DWORD devType;
		unsigned long productData1;
	};


	LPDIRECTINPUT8 g_DirectInput;
	HWND g_HWND;
	InputManager* InputManager::s_instance;
	bool InputManager::s_isInitialized = false;
	vector<GUID_Impl> g_GUIDs;
	
	bool InputManager::IsInitialized()
	{
		return s_isInitialized;
	}
	bool InputManager::Initialize()
	{
		if (!IsInitialized())
		{
			g_HWND = GetActiveWindow();
			HRESULT hr;
			HINSTANCE hInstance = GetModuleHandle(nullptr);

			hr = DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&g_DirectInput, NULL);

			if (FAILED(hr))
			{
				return false;
			}

			s_instance = new InputManager();


			s_isInitialized = true;
			return true;
		}
		return false;
	}
	void InputManager::Cleanup()
	{
		if (IsInitialized())
		{
			delete s_instance;
			s_instance = nullptr;
			g_DirectInput->Release();
			s_isInitialized = false;
		}
	}
	InputManager* InputManager::GetInstance()
	{
		if (!s_isInitialized)
			Initialize();
		return s_instance;
	}


	// Implementation of Input Devices
	class Keyboard_Impl : public Keyboard
	{
	public:
		Keyboard_Impl()
		{
			HRESULT hr;

			hr = g_DirectInput->CreateDevice(GUID_SysKeyboard, &m_Device, NULL);
			if (FAILED(hr))
			{
			}
			hr = m_Device->SetDataFormat(&c_dfDIKeyboard);
			if (FAILED(hr))
			{
			}
			hr = m_Device->SetCooperativeLevel(g_HWND, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);
			if (FAILED(hr))
			{
			}
		}
		~Keyboard_Impl()
		{
			m_Device->Unacquire();
		}
		virtual void Update() override final
		{
			HRESULT hr;
			hr = m_Device->Acquire();
			memcpy(m_PreviousState, m_CurrentState, sizeof(BYTE) * 256);
			m_Device->GetDeviceState(sizeof(m_CurrentState), (LPVOID)&m_CurrentState);
		}
		virtual bool GetKey(const InputKey a_Key) override final
		{
			return (m_CurrentState[a_Key] & 0x80) != 0;
		}
		virtual bool GetKeyDown(const InputKey a_Key) override final
		{
			return m_CurrentState[a_Key] & 0x80 && !(m_PreviousState[a_Key] & 0x80);
		}
		
	private:
		IDirectInputDevice8* m_Device;
		BYTE m_CurrentState[256];
		BYTE m_PreviousState[256];
	};
	class Joystick_Impl : public Joystick
	{
	public:
		Joystick_Impl(IDirectInputDevice8* a_Device)
		{
			HRESULT hr;

			m_Device = a_Device;

			hr = m_Device->SetDataFormat(&c_dfDIJoystick);
			if (FAILED(hr))
			{
			}
			hr = m_Device->SetCooperativeLevel(g_HWND, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
			if (FAILED(hr))
			{
			}
		}
		virtual ~Joystick_Impl()
		{
			m_Device->Unacquire();
			m_Device->Release();
		}
		virtual void Update() override final
		{
			HRESULT hr;

			m_PreviousState = m_CurrentState;
			hr = m_Device->Acquire();
			if (FAILED(hr))
			{
				m_IsValid = false;
				return;
			}
			hr = m_Device->GetDeviceState(sizeof(DIJOYSTATE), (LPVOID)&m_CurrentState);
			if (FAILED(hr))
			{
				m_IsValid = false;
				return;
			}
			m_IsValid = true;
		}
		virtual bool IsValid() override final
		{
			return m_IsValid;
		}
		virtual bool GetButton(const InputJoystickButton a_JoystickButton)
		{
			return (m_CurrentState.rgbButtons[a_JoystickButton] & 0x80) != 0;
		}
		virtual bool GetButton(const InputJoystickPhysical a_JoystickButton)
		{
			return false;
		}
		virtual bool GetButtonDown(const InputJoystickButton a_JoystickButton)
		{
			return m_CurrentState.rgbButtons[a_JoystickButton] & 0x80 && !(m_PreviousState.rgbButtons[a_JoystickButton] & 0x80);
		}
		virtual bool GetButtonDown(const InputJoystickPhysical a_JoystickButton)
		{
			return false;
		}
		virtual bool GetButtonUp(const InputJoystickButton a_JoystickButton)
		{
			return m_PreviousState.rgbButtons[a_JoystickButton] & 0x80 && !(m_CurrentState.rgbButtons[a_JoystickButton] & 0x80);
		}
		virtual bool GetButtonUp(const InputJoystickPhysical a_JoystickButton)
		{
			return false;
		}
		virtual TeaLib::Math::Vector2f GetDelta(const InputJoystickAxis a_InputStick)
		{
			if (IsValid())
			{
				switch (a_InputStick)
				{
				case Input::IJA_LSTICK:
					return TeaLib::Math::Vector2f((float)m_CurrentState.lX, (float)m_CurrentState.lY) / 32767.0f;
				case Input::IJA_RSTICK:
					return TeaLib::Math::Vector2f((float)m_CurrentState.lRx, (float)m_CurrentState.lRy) / 32767.0f;
				case Input::IJA_LRTRIGGER:
					return TeaLib::Math::Vector2f((float)m_CurrentState.lZ, (float)m_CurrentState.lRz) / 32767.0f;
				default:
					return TeaLib::Math::Vector2f();
				}
			}
			return TeaLib::Math::Vector2f();
		}
		virtual InputDeviceType GetDeviceType()
		{
			return IDT_NOTDEFINED;
		}
	protected:
		bool m_IsValid = false;
		IDirectInputDevice8* m_Device;
		DIJOYSTATE m_CurrentState, m_PreviousState;
	};
	class JoystickDS4_Impl : public Joystick_Impl
	{
	public:
		JoystickDS4_Impl(IDirectInputDevice8* a_Device) : Joystick_Impl(a_Device)
		{
			m_PhysicalBindings[IJP_FACEDOWN] = IJB_DS4CROSS;
			m_PhysicalBindings[IJP_FACERIGHT] = IJB_DS4CIRCLE;
			m_PhysicalBindings[IJP_FACELEFT] = IJB_BUTTON0;
			m_PhysicalBindings[IJP_FACEUP] = IJB_BUTTON3;
			m_PhysicalBindings[IJP_DPADDOWN] = IJB_DS4DPADDOWN;
			m_PhysicalBindings[IJP_DPADRIGHT] = IJB_DS4DPADRIGHT;
			m_PhysicalBindings[IJP_DPADLEFT] = IJB_DS4DPADLEFT;
			m_PhysicalBindings[IJP_DPADUP] = IJB_DS4DPADUP;
			m_PhysicalBindings[IJP_SHOULDERRIGHT] = IJB_DS4R1;
			m_PhysicalBindings[IJP_SHOULDERLEFT] = IJB_DS4L1;
			m_PhysicalBindings[IJP_TRIGGERRIGHT] = IJB_DS4R2;
			m_PhysicalBindings[IJP_TRIGGERLEFT] = IJB_DS4L2;
			m_PhysicalBindings[IJP_START] = IJB_DS4OPTIONS;
			m_PhysicalBindings[IJP_SELECT] = IJB_DS4SHARE;
			m_PhysicalBindings[IJP_STICKLEFT] = IJB_DS4LEFTSTICK;
			m_PhysicalBindings[IJP_STICKRIGHT] = IJB_DS4RIGHTSTICK;
		}
		virtual bool GetButton(const InputJoystickButton a_JoystickButton) override final
		{
			if (a_JoystickButton < 200)
				return (m_CurrentState.rgbButtons[a_JoystickButton] & 0x80) != 0;
			else
			{
				switch (a_JoystickButton)
				{
				case Input::IJB_DS4DPADUP:
					if (m_CurrentState.rgdwPOV[0] < 36000 && m_CurrentState.rgdwPOV[0] > 27000 || m_CurrentState.rgdwPOV[0] < 9000)
						return true;
					break;
				case Input::IJB_DS4DPADRIGHT:
					if (m_CurrentState.rgdwPOV[0] > 0 && m_CurrentState.rgdwPOV[0] < 18000)
						return true;
					break;
				case Input::IJB_DS4DPADDOWN:
					if (m_CurrentState.rgdwPOV[0] > 9000 && m_CurrentState.rgdwPOV[0] < 27000)
						return true;
					break;
				case Input::IJB_DS4DPADLEFT:
					if (m_CurrentState.rgdwPOV[0] > 18000 && m_CurrentState.rgdwPOV[0] < 36000)
						return true;
					break;
				default:
					break;
				}
				return false;
			}
		}
		virtual bool GetButton(const InputJoystickPhysical a_JoystickButton) override final
		{
			return GetButton(m_PhysicalBindings[a_JoystickButton]);
		}
		virtual bool GetButtonDown(const InputJoystickButton a_JoystickButton) override final
		{
			if (a_JoystickButton < 200)
				return m_CurrentState.rgbButtons[a_JoystickButton] & 0x80 && !(m_PreviousState.rgbButtons[a_JoystickButton] & 0x80);
			else
			{
				switch (a_JoystickButton)
				{
				case Input::IJB_DS4DPADUP:
					if (m_CurrentState.rgdwPOV[0] == 0 && m_PreviousState.rgdwPOV[0] != 0)
						return true;
					break;
				case Input::IJB_DS4DPADRIGHT:
					if (m_CurrentState.rgdwPOV[0] == 9000 && m_PreviousState.rgdwPOV[0] != 9000)
						return true;
					break;
				case Input::IJB_DS4DPADDOWN:
					if (m_CurrentState.rgdwPOV[0] == 18000 && m_PreviousState.rgdwPOV[0] != 18000)
						return true;
					break;
				case Input::IJB_DS4DPADLEFT:
					if (m_CurrentState.rgdwPOV[0] == 27000 && m_PreviousState.rgdwPOV[0] != 27000)
						return true;
					break;
				default:
					break;
				}
				return false;
			}
		}
		virtual bool GetButtonDown(const InputJoystickPhysical a_JoystickButton) override final
		{
			return GetButtonDown(m_PhysicalBindings[a_JoystickButton]);
		}
		virtual bool GetButtonUp(const InputJoystickButton a_JoystickButton) override final
		{
			if (a_JoystickButton < 200)
				return m_PreviousState.rgbButtons[a_JoystickButton] & 0x80 && !(m_CurrentState.rgbButtons[a_JoystickButton] & 0x80);
			else
			{
				switch (a_JoystickButton)
				{
				case Input::IJB_DS4DPADUP:
					if (m_PreviousState.rgdwPOV[0] == 0 && m_CurrentState.rgdwPOV[0] != 0)
						return true;
					break;
				case Input::IJB_DS4DPADRIGHT:
					if (m_PreviousState.rgdwPOV[0] == 9000 && m_CurrentState.rgdwPOV[0] != 9000)
						return true;
					break;
				case Input::IJB_DS4DPADDOWN:
					if (m_PreviousState.rgdwPOV[0] == 18000 && m_CurrentState.rgdwPOV[0] != 18000)
						return true;
					break;
				case Input::IJB_DS4DPADLEFT:
					if (m_PreviousState.rgdwPOV[0] == 27000 && m_CurrentState.rgdwPOV[0] != 27000)
						return true;
					break;
				default:
					break;
				}
				return false;
			}
		}
		virtual bool GetButtonUp(const InputJoystickPhysical a_JoystickButton) override final
		{
			return GetButtonUp(m_PhysicalBindings[a_JoystickButton]);
		}
		virtual TeaLib::Math::Vector2f GetDelta(const InputJoystickAxis a_InputStick) override final
		{
			if (IsValid())
			{
				float angle;
				switch (a_InputStick)
				{
				case Input::IJA_LSTICK:
					return TeaLib::Math::Vector2f((float)m_CurrentState.lX - 32767.0f, (float)m_CurrentState.lY - 32767.0f) / 32767.0f;
				case Input::IJA_RSTICK:
					return TeaLib::Math::Vector2f((float)m_CurrentState.lZ - 32767.0f, (float)m_CurrentState.lRz - 32767.0f) / 32767.0f;
				case Input::IJA_LRTRIGGER:
					return TeaLib::Math::Vector2f((float)m_CurrentState.lRx, (float)m_CurrentState.lRy) / 65534.0f;
				case Input::IJA_DPAD:
					if (m_PreviousState.rgdwPOV[0] < 90000)
					{
						angle = (((float)m_PreviousState.rgdwPOV[0] / 100.0f) * PI / 180.0f);
						return TeaLib::Math::Vector2f(sinf(angle), -cosf(angle));
					}
					return TeaLib::Math::Vector2f();
				default:
					return TeaLib::Math::Vector2f();
				}
			}
			return TeaLib::Math::Vector2f();
		}
		virtual InputDeviceType GetDeviceType() override final
		{
			return IDT_DS4;
		}
	private:
		map<InputJoystickPhysical, InputJoystickButton> m_PhysicalBindings;
	};
	class JoystickXbox360_Impl : public Joystick_Impl
	{
	public:
		JoystickXbox360_Impl(IDirectInputDevice8* a_Device) : Joystick_Impl(a_Device)
		{
			m_PhysicalBindings[IJP_FACEDOWN] = IJB_XBOXA;
			m_PhysicalBindings[IJP_FACERIGHT] = IJB_XBOXB;
			m_PhysicalBindings[IJP_FACELEFT] = IJB_XBOXX;
			m_PhysicalBindings[IJP_FACEUP] = IJB_XBOXY;
			m_PhysicalBindings[IJP_DPADDOWN] = IJB_XBOXDPADDOWN;
			m_PhysicalBindings[IJP_DPADRIGHT] = IJB_XBOXDPADRIGHT;
			m_PhysicalBindings[IJP_DPADLEFT] = IJB_XBOXDPADLEFT;
			m_PhysicalBindings[IJP_DPADUP] = IJB_XBOXDPADUP;
			m_PhysicalBindings[IJP_SHOULDERRIGHT] = IJB_XBOXRB;
			m_PhysicalBindings[IJP_SHOULDERLEFT] = IJB_XBOXLB;
			m_PhysicalBindings[IJP_TRIGGERRIGHT]	= IJB_XBOXRT;
			m_PhysicalBindings[IJP_TRIGGERLEFT]		= IJB_XBOXLT;
			m_PhysicalBindings[IJP_START] = IJB_XBOXSTART;
			m_PhysicalBindings[IJP_SELECT] = IJB_XBOXBACK;
			m_PhysicalBindings[IJP_STICKLEFT] = IJB_XBOXLEFTSTICK;
			m_PhysicalBindings[IJP_STICKRIGHT] = IJB_XBOXRIGHTSTICK;
		}
		virtual TeaLib::Math::Vector2f GetDelta(const InputJoystickAxis a_InputStick) override final
		{
			if (IsValid())
			{
				float result;
				float angle;
				switch (a_InputStick)
				{
				case Input::IJA_LSTICK:
					return TeaLib::Math::Vector2f((float)m_CurrentState.lX - 32767.0f, (float)m_CurrentState.lY - 32767.0f) / 32767.0f;
				case Input::IJA_RSTICK:
					return TeaLib::Math::Vector2f((float)m_CurrentState.lRx - 32767.0f, (float)m_CurrentState.lRy - 32767.0f) / 32767.0f;
				case Input::IJA_LRTRIGGER:
					result = ((float)m_CurrentState.lZ - 32767.0f) / 32767.0f;
					return TeaLib::Math::Vector2f(result, result);
				case Input::IJA_DPAD:
					if (m_PreviousState.rgdwPOV[0] < 90000)
					{
						angle = (((float)m_PreviousState.rgdwPOV[0] / 100.0f) * PI / 180.0f);
						return TeaLib::Math::Vector2f(sinf(angle), -cosf(angle));
					}
					return TeaLib::Math::Vector2f();
				default:
					return TeaLib::Math::Vector2f();
				}
			}
			return TeaLib::Math::Vector2f();
		}
		virtual bool GetButton(const InputJoystickButton a_JoystickButton) override final
		{
			if (a_JoystickButton < 200)
				return (m_CurrentState.rgbButtons[a_JoystickButton] & 0x80) != 0;
			else
			{
				float val;
				switch (a_JoystickButton)
				{
				case Input::IJB_XBOXDPADUP:
					if (m_CurrentState.rgdwPOV[0] < 36000 && m_CurrentState.rgdwPOV[0] > 27000 || m_CurrentState.rgdwPOV[0] < 9000)
						return true;
					break;
				case Input::IJB_XBOXDPADRIGHT:
					if (m_CurrentState.rgdwPOV[0] > 0 && m_CurrentState.rgdwPOV[0] < 18000)
						return true;
					break;
				case Input::IJB_XBOXDPADDOWN:
					if (m_CurrentState.rgdwPOV[0] > 9000 && m_CurrentState.rgdwPOV[0] < 27000)
						return true;
					break;
				case Input::IJB_XBOXDPADLEFT:
					if (m_CurrentState.rgdwPOV[0] > 18000 && m_CurrentState.rgdwPOV[0] < 36000)
						return true;
					break;
				case Input::IJB_XBOXLT:
					val = ((float)m_CurrentState.lZ - 32767.0f) / 32767.0f;;
					return val > 0.1f;
				case Input::IJB_XBOXRT:
					val = ((float)m_CurrentState.lZ - 32767.0f) / 32767.0f;;
					return val < -0.1f;
				default:
					break;
				}
				return false;
			}
		}
		virtual bool GetButton(const InputJoystickPhysical a_JoystickButton) override final
		{
			return GetButton(m_PhysicalBindings[a_JoystickButton]);
		}
		virtual bool GetButtonDown(const InputJoystickButton a_JoystickButton) override final
		{
			if (a_JoystickButton < 200)
				return m_CurrentState.rgbButtons[a_JoystickButton] & 0x80 && !(m_PreviousState.rgbButtons[a_JoystickButton] & 0x80);
			else
			{
				float curr, prev;
				switch (a_JoystickButton)
				{
				case Input::IJB_XBOXDPADUP:
					if (m_CurrentState.rgdwPOV[0] == 0 && m_PreviousState.rgdwPOV[0] != 0)
						return true;
					break;
				case Input::IJB_XBOXDPADRIGHT:
					if (m_CurrentState.rgdwPOV[0] == 9000 && m_PreviousState.rgdwPOV[0] != 9000)
						return true;
					break;
				case Input::IJB_XBOXDPADDOWN:
					if (m_CurrentState.rgdwPOV[0] == 18000 && m_PreviousState.rgdwPOV[0] != 18000)
						return true;
					break;
				case Input::IJB_XBOXDPADLEFT:
					if (m_CurrentState.rgdwPOV[0] == 27000 && m_PreviousState.rgdwPOV[0] != 27000)
						return true;
					break;
				case Input::IJB_XBOXLT:
					curr = ((float)m_CurrentState.lZ - 32767.0f) / 32767.0f;
					prev = ((float)m_PreviousState.lZ - 32767.0f) / 32767.0f;
					return curr > 0.1f && prev <= 0.1f;
				case Input::IJB_XBOXRT:
					curr = ((float)m_CurrentState.lZ - 32767.0f) / 32767.0f;
					prev = ((float)m_PreviousState.lZ - 32767.0f) / 32767.0f;
					return curr < -0.1f && prev >= -0.1f;
				default:
					break;
				}
				return false;
			}
		}
		virtual bool GetButtonDown(const InputJoystickPhysical a_JoystickButton) override final
		{
			if (m_PhysicalBindings.find(a_JoystickButton) != m_PhysicalBindings.end())
				return GetButtonDown(m_PhysicalBindings[a_JoystickButton]);
			return false;
		}
		virtual bool GetButtonUp(const InputJoystickButton a_JoystickButton) override final
		{
			if (a_JoystickButton < 200)
				return m_PreviousState.rgbButtons[a_JoystickButton] & 0x80 && !(m_CurrentState.rgbButtons[a_JoystickButton] & 0x80);
			else
			{
				float curr, prev;
				switch (a_JoystickButton)
				{
				case Input::IJB_XBOXDPADUP:
					if (m_PreviousState.rgdwPOV[0] == 0 && m_CurrentState.rgdwPOV[0] != 0)
						return true;
					break;
				case Input::IJB_XBOXDPADRIGHT:
					if (m_PreviousState.rgdwPOV[0] == 9000 && m_CurrentState.rgdwPOV[0] != 9000)
						return true;
					break;
				case Input::IJB_XBOXDPADDOWN:
					if (m_PreviousState.rgdwPOV[0] == 18000 && m_CurrentState.rgdwPOV[0] != 18000)
						return true;
					break;
				case Input::IJB_XBOXDPADLEFT:
					if (m_PreviousState.rgdwPOV[0] == 27000 && m_CurrentState.rgdwPOV[0] != 27000)
						return true;
					break;
				case Input::IJB_XBOXLT:
					curr = ((float)m_CurrentState.lZ - 32767.0f) / 32767.0f;
					prev = ((float)m_PreviousState.lZ - 32767.0f) / 32767.0f;
					return curr <= 0.1f && prev > 0.1f;
				case Input::IJB_XBOXRT:
					curr = ((float)m_CurrentState.lZ - 32767.0f) / 32767.0f;
					prev = ((float)m_PreviousState.lZ - 32767.0f) / 32767.0f;
					return curr >= -0.1f && prev < -0.1f;
				default:
					break;
				}
				return false;
			}
		}
		virtual bool GetButtonUp(const InputJoystickPhysical a_JoystickButton) override final
		{
			if (m_PhysicalBindings.find(a_JoystickButton) != m_PhysicalBindings.end())
				return GetButtonUp(m_PhysicalBindings[a_JoystickButton]);
			return false;
		}
		virtual InputDeviceType GetDeviceType() override final
		{
			return IDT_XBOX;
		}
	private:
		map<InputJoystickPhysical, InputJoystickButton> m_PhysicalBindings;
	};

	InputManager::InputManager() : joystick(nullptr)
	{
		keyboard = new Keyboard_Impl();
	}

	void InputManager::Update()
	{
		keyboard->Update();
		if (joystick)
		{
			joystick->Update();
			
			if (joystick->IsValid())
			{
				for (auto it : m_joystickCallbacks)
				{
					switch (it.first.second)
					{
					case IME_PRESSED:
						if (joystick->GetButtonDown(it.first.first))
						{
							it.second->Call();
						}
						break;
					case IME_RELEASED:
						if (joystick->GetButtonUp(it.first.first))
						{
							it.second->Call();
						}
						break;
					case IME_REPEAT:
						if (joystick->GetButton(it.first.first))
						{
							it.second->Call();
						}
						break;
					}
				}
			}
		}
	}
	BOOL __stdcall JoystickEnumCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef)
	{
		InputManager* inputInstance = InputManager::GetInstance();

		inputInstance->AddJoystickName(lpddi->tszProductName);

		GUID_Impl newGUID;
		newGUID.devType = lpddi->dwDevType;
		newGUID.instance = lpddi->guidInstance;
		newGUID.productData1 = lpddi->guidProduct.Data1;

		g_GUIDs.push_back(newGUID);

		return DIENUM_CONTINUE;
	}

	void InputManager::AddJoystickName(std::wstring a_name)
	{
		m_joystickNames.push_back(a_name);
	}

	void InputManager::SearchForJoystick()
	{
		m_joystickNames.clear();
		g_GUIDs.clear();
		g_DirectInput->EnumDevices(DI8DEVCLASS_GAMECTRL, &JoystickEnumCallback, NULL, DIEDFL_ATTACHEDONLY);
	}

	vector<wstring>& InputManager::GetJoystickNames()
	{
		return m_joystickNames;
	}

	void InputManager::ConnectJoystickByIndex(size_t a_index)
	{
		if (joystick)
			delete joystick;

		if (a_index >= g_GUIDs.size())
			return;

		HRESULT hr;
		IDirectInputDevice8* device;
		hr = g_DirectInput->CreateDevice(g_GUIDs[a_index].instance, &device, NULL);
		if (!FAILED(hr))
		{
			if (g_GUIDs[a_index].devType == DUALSHOCK4DEVTYPE || g_GUIDs[a_index].productData1 == DUALSHOCK4PRODUCTDATA)
				joystick = new JoystickDS4_Impl(device);
			else if (g_GUIDs[a_index].devType == WIREDXBOXDEVTYPE)
				joystick = new JoystickXbox360_Impl(device);
			else
				joystick = new Joystick_Impl(device);
		}
	}

	InputManager::~InputManager()
	{
		delete keyboard;
		delete joystick;
		ClearCallbacks();
	}

	void InputManager::ClearCallbacks()
	{
		for (auto it : m_joystickCallbacks)
		{
			delete it.second;
		}
		m_joystickCallbacks.clear();
	}
}

#endif