/*
 * Copyright (c) 2012-2025 Daniele Bartolini et al.
 * SPDX-License-Identifier: MIT
 */

#pragma once

#include "core/math/types.h"
#include "core/memory/types.h"
#include "core/strings/string_id.h"
#include "core/types.h"
#include "device/input_types.h"

namespace crown
{
/// Represents a generic input device.
///
/// @ingroup Input
struct InputDevice
{
	bool _connected;
	u8 _num_buttons;
	u8 _num_axes;
	u8 _first_button[2];
	const char **_button_name;
	const char **_axis_name;

	u8 *_state;               // num_buttons
	Vector3 *_axis;           // num_axes
	u32 *_deadzone_mode;      // num_axes
	f32 *_deadzone_size;      // num_axes
	StringId32 *_button_hash; // num_buttons
	StringId32 *_axis_hash;   // num_axes
	char *_name;              // strlen32(name) + 1
	int _lua_object;

	void set_button(u8 id, u8 state);
	void set_axis(u8 id, f32 x, f32 y, f32 z);
	void update();

	/// Returns the name of the input device.
	const char *name() const;

	/// Returns whether the input device is connected and functioning.
	bool connected() const;

	/// Returns the number of buttons of the input device.
	u8 num_buttons() const;

	/// Returns the number of axes of the input devices.
	u8 num_axes() const;

	/// Returns whether the button @a id is pressed in the current frame.
	bool pressed(u8 id) const;

	/// Returns whether the button @a id is released in the current frame.
	bool released(u8 id) const;

	/// Returns the id of the first button that was pressed in the current frame
	/// or UINT8_MAX if no buttons were pressed at all.
	u8 any_pressed() const;

	/// Returns the id of the first button that was released in the current frame
	/// or UINT8_MAX if no buttons were released at all.
	u8 any_released() const;

	/// Returns the value of the button @a id in the range [0..1].
	f32 button(u8 id) const;

	/// Returns the value of the axis @a id.
	Vector3 axis(u8 id) const;

	/// Returns the name of the button @a id or NULL if no matching button is found.
	const char *button_name(u8 id) const;

	/// Returns the name of the axis @a id of NULL if no matching axis is found.
	const char *axis_name(u8 id) const;

	/// Returns the id of the button @a name or UINT8_MAX if no matching button is found.
	u8 button_id(StringId32 name) const;

	/// Returns the id of the axis @a name of UINT8_MAX if no matching axis is found.
	u8 axis_id(StringId32 name) const;

	/// Returns the deadzone size and the deadzone @a mode for the axis @a id.
	f32 deadzone(u8 id, DeadzoneMode::Enum *deadzone_mode) const;

	/// Sets the @a deadzone_mode and @a deadzone_size for the axis @a id.
	void set_deadzone(u8 id, DeadzoneMode::Enum deadzone_mode, f32 deadzone_size);
};

/// Functions to manipulate InputDevice.
///
/// @ingroup Input
namespace input_device
{
	/// Creates a new input device.
	InputDevice *create(Allocator &a, const char *name, u8 num_buttons, u8 num_axes, const char **button_names, const char **axis_names);

	/// Destroys the input device @a id.
	void destroy(Allocator &a, InputDevice &id);

} // namespace input_device

} // namespace crown
