/*
 Copyright (c) 2026 - SD-Innovation S.A.S. - FRANCE
*/

/*
ver: 2.x.x - build: 2026-04-28
*/

/*
The zlib License

Copyright (c) 2026 SD-Innovation S.A.S.

This software is provided ‘as-is’, without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.

2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.

3. This notice may not be removed or altered from any source
distribution.
*/

#pragma once

#include "defs.h"

namespace sdi_toolBox::desktop::eventBus
{
//--------------------------------------------------------------
/**
 * @class Message
 * @brief Base class for all messages dispatched through the event bus.
 *
 * Every message circulating in the event bus system must derive from this class.
 * It carries a unique message type identifier (@ref MessageTypeID) used by the
 * @ref Bus to route the message to the appropriate subscribers, and a timestamp
 * that is updated when the message is posted to the bus.
 *
 * @note The Message class is non-copyable and non-movable.
 * @note The default constructor is deleted: a @ref MessageTypeID must always
 *       be provided at construction time.
 * @note The timestamp is set by the @ref Bus internally when @ref Bus::post()
 *       is called; it is not set at construction time.
 *
 * @par Example - defining a custom message:
 * @code
 * static constexpr sdi_toolBox::desktop::eventBus::MessageTypeID MY_EVENT = 1;
 *
 * struct MyMessage : public sdi_toolBox::desktop::eventBus::Message
 * {
 *   explicit MyMessage(int value)
 *     : Message(MY_EVENT)
 *     , payload(value)
 *   {}
 *   int payload{};
 * };
 * @endcode
 *
 * @see Bus
 * @see MessageTypeID
 * @see TimePoint
 */
class Message
{
  friend class Bus;     ///< Allow the Bus class to access private members

  public:
  ///@name Construction & Destruction
  ///@{

  /**
   * @brief Default constructor - deleted.
   *
   * A @ref MessageTypeID must always be provided at construction time.
   */
  Message() = delete;

  /**
   * @brief Default destructor.
   */
  virtual ~Message() = default;

  /**
   * @brief Copy constructor - deleted.
   *
   * Message is non-copyable.
   */
  Message(const Message &obj) = delete;

  /**
   * @brief Move constructor - deleted.
   *
   * Message is non-movable.
   */
  Message(Message &&obj) noexcept = delete;

  /**
   * @brief Copy assignment operator - deleted.
   *
   * Message is non-copyable.
   */
  Message &operator=(const Message &obj) = delete;

  /**
   * @brief Move assignment operator - deleted.
   *
   * Message is non-movable.
   */
  Message &operator=(Message &&obj) noexcept = delete;

  /**
   * @brief Construct a message with the given type identifier.
   *
   * @param messageTypeID Unique identifier representing the type of this message.
   *                      Used by the @ref Bus to route the message to the correct
   *                      subscribers.
   */
  explicit Message(MessageTypeID messageTypeID);

  ///@}
  ///@name Accessors
  ///@{

  /**
   * @brief Get the unique type identifier of this message.
   *
   * @return The @ref MessageTypeID assigned at construction time.
   */
  [[nodiscard]] MessageTypeID getMessageTypeID() const;

  /**
   * @brief Get the timestamp of when this message was posted to the bus.
   *
   * The timestamp is recorded by the @ref Bus when @ref Bus::post() is called.
   * It is left at its default-constructed (zero) value if the message has not
   * yet been posted.
   *
   * @return A @ref TimePoint representing the moment the message was dispatched.
   * @see Bus::post()
   */
  [[nodiscard]] TimePoint getTimestamp() const;

  ///@}

  private:
  /**
   * @brief Update the message timestamp to the current time.
   *
   * Called internally by @ref Bus::post() just before the message is dispatched
   * to subscribers. Not accessible from outside the bus.
   */
  void updateTimestamp();

  MessageTypeID m_messageTypeID;              ///< Unique identifier for the message type
  TimePoint     m_messagePostTimestamp{};     ///< Timestamp of when the message was posted to the bus
};
//--------------------------------------------------------------

//--------------------------------------------------------------
/* Constructor */
inline Message::Message(const MessageTypeID messageTypeID)
{
  m_messageTypeID = messageTypeID;
}
//--------------------------------------------------------------
/* Get the unique identifier for the message type */
inline MessageTypeID Message::getMessageTypeID() const
{
  return m_messageTypeID;
}
//--------------------------------------------------------------
/* Get the timestamp of when the message was posted to the bus */
inline TimePoint Message::getTimestamp() const
{
  return m_messagePostTimestamp;
}
//--------------------------------------------------------------
/* Update the timestamp of when the message was posted to the bus */
inline void Message::updateTimestamp()
{
  m_messagePostTimestamp = std::chrono::steady_clock::now();
}
//--------------------------------------------------------------
}     // namespace sdi_toolBox::desktop::eventBus
