/*
 * 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/.
 */

#pragma once

#include "InputDevice.hpp"

namespace OpenVulkano::Input
{
	class ControllerType
	{
	public:
		enum Type { GENERIC_JOYSTICK, XBOX, DUAL_SHOCK, DUAL_SENSE };

	private:
		Type type;

	public:
		ControllerType(Type type) : type(type) {}
	};

	class InputDeviceController : public InputDevice
	{
		float axes[InputKey::Controller::Axis::AXIS_LAST + 1] = {0};
		uint32_t pressedButtons = 0, lastPressedButtons = 0;
		const ControllerType controllerType = ControllerType::GENERIC_JOYSTICK;

		[[nodiscard]] bool GetLastButton(InputKey::Controller::Button button) const
		{
			return lastPressedButtons & (1 << button);
		}

	protected:
		InputDeviceController() = default;

		void Init(int index, const std::string& name);

		void SetAxis(InputKey::Controller::Axis axisId, float value)
		{
			axes[axisId] = value;
		}

		void SetButtons(uint32_t buttonStates)
		{
			lastPressedButtons = pressedButtons;
			pressedButtons = buttonStates;
		}

		[[nodiscard]] float ReadAxis(int16_t key) const final
		{
			return GetAxis(static_cast<InputKey::Controller::Axis>(key));
		}

		[[nodiscard]] bool ReadButton(int16_t key) const final
		{
			return GetButton(static_cast<InputKey::Controller::Button>(key));
		}

		[[nodiscard]] bool ReadButtonUp(int16_t key) const final
		{
			return GetButtonUp(static_cast<InputKey::Controller::Button>(key));
		}

		[[nodiscard]] bool ReadButtonDown(int16_t key) const final
		{
			return GetButtonDown(static_cast<InputKey::Controller::Button>(key));
		}

	public:
		[[nodiscard]] bool GetButton(const InputKey::Controller::Button button) const
		{
			return pressedButtons & (1 << button);
		}

		[[nodiscard]] bool GetButtonUp(const InputKey::Controller::Button button) const
		{
			return !GetButton(button) && GetLastButton(button);
		}

		[[nodiscard]] bool GetButtonDown(const InputKey::Controller::Button button) const
		{
			return GetButton(button) && !GetLastButton(button);
		}

		[[nodiscard]] float GetAxis(const InputKey::Controller::Axis axis) const
		{
			return axes[axis];
		}

		[[nodiscard]] ControllerType GetControllerType() const
		{
			return controllerType;
		}
	};
}
