//===-- core/MessagingSystemImpl.hpp ----------------------------*- C++ -*-===//
//
//                                 The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file core/MessagingSystemImpl.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Declaration of a basic implementation of the \c rosa::MessagingSystem
/// interface.
///
//===----------------------------------------------------------------------===//

#ifndef ROSA_LIB_CORE_MESSAGINGSYSTEMIMPL_HPP
#define ROSA_LIB_CORE_MESSAGINGSYSTEMIMPL_HPP

#include "SystemImpl.hpp"

#include "rosa/core/MessagingSystem.hpp"

namespace rosa {

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

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

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

  bool operator==(const System &Other) const noexcept override {
    return Base::operator==(Other);
  }

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

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

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

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

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

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

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

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

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

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

  ///@}

  /// Sends a \c rosa::message_t instance to the \c rosa::Agent instance
  /// referred by a \c rosa::AgentHandle -- by directly invoking the
  /// \c rosa::Agent instance with the \c rosa::Message object.
  ///
  /// \note If the given \c rosa::Message object cannot be handled by the
  /// referred \c rosa::Agent instance, the \c rosa::Message object is simply
  /// ignored.
  ///
  /// \param H refers to the \c rosa::Agent instance to send to
  /// \param M message to send
  ///
  /// \pre The referred \c rosa::Agent instance is owned by \p 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
