// Copyright 2023 Embedded Artistry LLC
// SPDX-License-Identifier: GPL-3.0-only OR Embedded Virtual Machine Commercial License

#ifndef EVENT_BASE_TYPES_HPP_
#define EVENT_BASE_TYPES_HPP_

#include <etl/message.h>
#include <functional>

/// Alias for the underlying event ID type. This should be used
/// for defining events that work with this event model.
using event_id_t = etl::message_id_t;

/// Alias for the underlying event base type, as referenced
/// in interfaces.
using event_t = etl::imessage;

/// These event IDs are reserved for the core system
/// and should not be defined by application code.
enum ReservedEventIDs : event_id_t {
	Callable = 0xFF
};

/** Base class for events
 *
 * This base class augments the basic etl::imessage support by adding
 * additional data that we want to use for our purposes.
 *
 * For convenience, a helper alias `EventBase` is defined that simplifies the inheritance:
 *
 * @code
 * struct GPSPositionReadyEvent : public EventBase<ID_GPSNewPositionReady>
 * @encode
 *
 * You can also use the standard etl::message inheritance scheme:
 *
 * @code
 * struct GPSPositionReadyEvent : public etl::message<GPSTimestampReadyEvent, EventBase_t>
 * @endcode
 *
 * If you don't wish to use this event base, just leave it out of the declaration:
 *
 * @code
 * struct GPSPositionReadyEvent : public etl::message<GPSTimestampReadyEvent>
 * @endcode
 */
struct EventBase_t : public event_t
{
    // If you want events to have some common aspect,
    // such as a source ID value, then you should add it here.
};

/** Convenience alias for EventBase_t
 *
 * This alias simplifies the declaration of events by providing a template
 * that eliminates the etl::message inheritance boilerplate.
 *
 * @code
 * struct GPSPositionReadyEvent : public EventBase<GPSNewPositionReady_ID>
 * @endcode
 *
 * @tparam TId The ID of the event
 */
template<etl::message_id_t TId>
using EventBase = etl::message<TId, EventBase_t>;

/// A Callable Event represents a function that should be executed on the main
/// thread of execution. It can be added to the event queue and processed in a
/// serialized manner as with other events.
struct CallableEvent : public EventBase<ReservedEventIDs::Callable>
{
	using callable_func_t = std::function<void(void)>;

	CallableEvent() = default;
	CallableEvent(callable_func_t func) : callable(func) {}
	callable_func_t callable;
};

#endif // EVENT_BASE_TYPES_HPP_
