/***************************************************************************//**
 *
 * \file core/MessagingSystemImpl.hpp
 *
 * \author David Juhasz (david.juhasz@tuwien.ac.at)
 *
 * \date 2017
 *
 * \brief Declaration of a basic implementation of the `rosa::MessagingSystem`
 *        interface.
 *
 ******************************************************************************/

#ifndef ROSA_LIB_CORE_MESSAGINGSYSTEMIMPL_HPP // NOLINT
#define ROSA_LIB_CORE_MESSAGINGSYSTEMIMPL_HPP

#include "SystemImpl.hpp"

#include "rosa/core/MessagingSystem.hpp"

namespace rosa {

/// Implements `rosa::MessagingSystem` by extending `rosa::SystemImpl` with
/// adding a simple implementation of sending messages: directly invoking
/// `rosa::Agent` instances with given `rosa::Message` objects.
///
/// \note Keep in mind that sending a `rosa::Message` object with this
/// implementation translates into a direct function call.
class MessagingSystemImpl : public MessagingSystem, public SystemImpl {
  /// Alies for the base-class `rosa::SystemImpl`.
  using Base = SystemImpl;

public:
  /// Creates an instance.
  ///
  /// \param Name name of the new instance
  MessagingSystemImpl(const std::string &Name) noexcept;

protected:
  /// \defgroup `rosa::MessagingSystemImpl` call forwardings
  ///
  /// \note Simply forwarding calls to implementations provided by
  /// `rosa::MessagingSystem::Base˙ for the `rosa::System` interface.
  ///
  /// \todo How could we use the inherited implementations in a simpler way?
  ///@{

  inline id_t nextId(void) noexcept override { return Base::nextId(); }

  inline bool isSystemCleaned(void) const noexcept override {
    return Base::isSystemCleaned();
  }

  inline void markCleaned(void) noexcept override { Base::markCleaned(); }

  inline void registerUnit(Unit &U) noexcept override { Base::registerUnit(U); }

  inline void destroyUnit(Unit &U) noexcept override { Base::destroyUnit(U); }

  inline bool isUnitRegistered(const Unit &U) const noexcept override {
    return Base::isUnitRegistered(U);
  }

public:
  inline const std::string &name(void) const noexcept override {
    return Base::name();
  }

  inline size_t numberOfConstructedUnits(void) const noexcept override {
    return Base::numberOfConstructedUnits();
  }

  inline size_t numberOfLiveUnits(void) const noexcept override {
    return Base::numberOfLiveUnits();
  }

  inline bool empty(void) const noexcept override { return Base::empty(); }

  ///@}

  /// Sends a `rosa::message_t` instance to the `rosa::Agent`instance referred
  /// by a `rosa::AgentHandle` -- by directly invoking the `rosa::Agent`
  /// instance with the `rosa::Message` object.
  ///
  /// \note If the given `rosa::Message` object cannot be handled by the
  /// referred `rosa::Agent` instance, the `rosa::Message` object is simply
  /// ignored.
  ///
  /// \param H refers to the `rosa::Agent` instance to send to
  /// \param M message to send
  ///
  /// \pre The referred `rosa::Agent` instance is owned by `this` object and
  /// also registered: \code
  /// &unwrapSystem(H) == this && isUnitRegistered(unwrapAgent(H))
  /// \endcode
  void send(const AgentHandle &H, message_t &&M) noexcept override;
};

} // End namespace rosa

#endif // ROSA_LIB_CORE_MESSAGINGSYSTEMIMPL_HPP

