//===-- rosa/deluxe/DeluxeSensor.hpp ----------------------------*- C++ -*-===//
//
//                                 The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/deluxe/DeluxeSensor.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Specialization of \c rosa::Agent for *sensor* role of the the *deluxe
/// interface*.
///
/// \see \c rosa::deluxe::DeluxeContext
///
//===----------------------------------------------------------------------===//

#ifndef ROSA_DELUXE_DELUXESENSOR_HPP
#define ROSA_DELUXE_DELUXESENSOR_HPP

#include "rosa/core/Agent.hpp"

#include "rosa/deluxe/DeluxeAtoms.hpp"
#include "rosa/deluxe/DeluxeExecutionPolicy.h"
#include "rosa/deluxe/DeluxeTuple.hpp"

/// Local helper macros to deal with built-in types.
///
///@{

/// Creates function name for member functions in \c rosa::deluxe::DeluxeSensor.
///
/// \param N name suffix to use
#define DSMASTERHANDLERNAME(N) handleMaster_##N

/// Defines member functions for handling messages from *master* in
/// \c rosa::deluxe::DeluxeSensor.
///
/// \see \c DeluxeSensorMasterInputHandlers
///
/// \note No pre- and post-conditions are validated directly by these functions,
/// they rather rely on \c rosa::deluxe::DeluxeSensor::saveMasterInput to do
/// that.
///
/// \param T the type of input to handle
/// \param N name suffix for the function identifier
#define DSMASTERHANDLERDEFN(T, N)                                              \
  void DSMASTERHANDLERNAME(N)(atoms::Master, id_t MasterId, token_size_t Pos,  \
                              T Value) noexcept {                              \
    saveMasterInput(MasterId, Pos, Value);                                     \
  }

/// Convenience macro for \c DSMASTERHANDLERDEFN with identical arguments.
///
/// \see \c DSMASTERHANDLERDEFN
///
/// This macro can be used instead of \c DSMASTERHANDLERDEFN if the actual value
/// of \p T can be used as a part of a valid identifier.
///
/// \param T the type of input to handle
#define DSMASTERHANDLERDEF(T) DSMASTERHANDLERDEFN(T, T)

/// Results in a \c THISMEMBER reference to a member function defined by
/// \c DSMASTERHANDLERDEFN.
///
/// Used in the constructor of \c rosa::deluxe::DeluxeSensor to initialize super
/// class \c rosa::Agent with member function defined by \c DSMASTERHANDLERDEFN.
///
/// \see \c DSMASTERHANDLERDEFN, \c THISMEMBER
///
/// \param N name suffix for the function identifier
#define DSMASTERHANDLERREF(N) THISMEMBER(DSMASTERHANDLERNAME(N))

///@}

namespace rosa {
namespace deluxe {

/// Specialization of \c rosa::Agent for *sensor* role of the *deluxe
/// interface*.
///
/// \see \c rosa::deluxe::DeluxeContext
///
/// \invariant There is a compatible *execution policy* set; the actual value in
/// \c rosa::deluxe::DeluxeSensor::MasterInputNextPos is valid with respect to
/// the corresponding types.
///
/// \see Definition of \c rosa::deluxe::DeluxeSensor::inv on the class invariant
///
/// \note All member functions validate the class invariant as part of their
/// precondition. Moreover, non-const functions validate the invariant before
/// return as their postcondition.
class DeluxeSensor : public Agent {
  /// Checks whether \p this object holds the class invariant.
  ///
  /// \see Invariant of the class \c rosa::deluxe::DeluxeSensor
  ///
  /// \return if \p this object holds the class invariant
  bool inv(void) const noexcept;

  /// The \c rosa::deluxe::DeluxeExecutionPolicy that controls the execution of
  /// \c this object.
  std::unique_ptr<DeluxeExecutionPolicy> ExecutionPolicy;

public:
  /// The type of values produced by \p this object.
  ///
  /// That is the types of values \p this object sends to its *master* in a
  /// \c rosa::deluxe::DeluxeTuple.
  ///
  /// \see \c rosa::deluxe::DeluxeSensor::master
  const Token OutputType;

  /// The type of values \p this object processes from its *master*.
  ///
  /// That is the types of values \p this object receives from its *master* in a
  /// \c rosa::deluxe::DeluxeTuple.
  ///
  /// \see \c rosa::deluxe::DeluxeSensor::master
  const Token MasterInputType;

private:
  /// Indicates which element of the master-input is expected from the *master*.
  ///
  /// The *master* is supposed to send one \c rosa::deluxe::DeluxeTuple value
  /// element by element in their order of definition. This member field tells
  /// the element at which position should be received next.
  ///
  /// \p this object is supposed to be triggered only when a complete
  /// master-input has been received, that is the field should hold the value
  /// `0`.
  ///
  /// \see \c rosa::deluxe::DeluxeSensor::handleTrigger
  /// \c rosa::deluxe::DeluxeSensor::saveMasterInput
  token_size_t MasterInputNextPos;

  /// Indicates whether the input value from the *master* has been changed since
  /// the last trigger received from the system.
  ///
  /// The flag is reset to \c false upon handling a trigger and then set to \c
  /// true by \c rosa::deluxe::DeluxeSensor::saveMasterInput when storig a new
  /// input value in \c rosa::deluxe::DeluxeSensor::MasterInputValue.
  bool MasterInputChanged;

  /// Stores the actual input value from *master*.
  ///
  /// \note The type of the stored value matches the types indicated by \c
  /// rosa::deluxe::DeluxeSensor::MasterInputType.
  const std::unique_ptr<AbstractTokenizedStorage> MasterInputValue;

  /// Alias for function objects used as trigger handler for
  /// \c rosa::deluxe::DeluxeSensor.
  ///
  /// \note The function used for \c H is to be \c noexcept.
  ///
  /// \see \c DeluxeSensorTriggerHandlers
  using H = std::function<void(void)>;

  /// \defgroup DeluxeSensorTriggerHandlers Trigger handlers of
  /// rosa::deluxe::DeluxeSensor
  ///
  /// \brief Trigger handler functions of \c rosa::deluxe::DeluxeSensor
  ///
  /// The actual data source functions and master-input processing function are
  /// captured in lambda expressions that are in turn wrapped in \c
  /// std::function objects. The lambda expression calls a processing function,
  /// either to handle master-input or obtain the next sensory value from data
  /// source. The next sensory value is sent it to *master* by calling \c
  /// rosa::deluxe::DeluxeSensor::sendToMaster. Also, the flag \c
  /// rosa::deluxe::DeluxeSensor::MasterInputChanged is reset when the current
  /// value is passed to the master-input processing function. The function \c
  /// rosa::deluxe::DeluxeSensor::handleTrigger needs only to call the proper
  /// function object.

  /// Processes master-input.
  ///
  /// \ingroup DeluxeSensorTriggerHandlers
  ///
  /// The function is called upon the sensor is trigged by the system.
  const H MFP;

  /// Produces the next sensory value during normal execution.
  ///
  /// \ingroup DeluxeSensorTriggerHandlers
  ///
  /// The function is used during normal execution. During simulation, the
  /// simulation environment sets \c rosa::deluxe::DeluxeSensor::SFP, which is
  /// used instead of \c rosa::deluxe::DeluxeSensor::FP.
  const H FP;

  /// Produces the next sensory value during simulation.
  ///
  /// \ingroup DeluxeSensorTriggerHandlers
  ///
  /// The function is empty by default. The simulation environment sets it to be
  /// used during simulation.
  H SFP;

  /// The *master* to send values to.
  ///
  /// \note *Masters* are set dynamically, hence it is possible that a
  /// \c rosa::deluxe::DeluxeSensor instance does not have any *master* at a
  /// given moment.
  Optional<AgentHandle> Master;

  /// Tells the unique identifier of the *master* of \p this object, if any
  /// registered.
  ///
  /// \return the unique identifier of the *master*
  ///
  /// \pre A *master* is registered for \p this object: \code
  /// Master
  /// \endcode
  id_t masterId(void) const noexcept;

  /// Wraps a master-input processing function into a trigger handler.
  ///
  /// \see \c rosa::deluxe::DeluxeSensor::MFP and \c DeluxeSensorTriggerHandlers
  ///
  /// \tparam Ts types of elements of master-input processed by \p MF
  /// \tparam S0 indices for accessing master-input values
  ///
  /// \param MF function that processes master-input
  ///
  /// \note The second argument provides indices statically as template
  /// arguments \p S0..., so its actual value is ignored.
  ///
  /// \note A master-input type of \c rosa::deluxe::EmptyDeluxeTuple indicates
  /// that \p this object does not receive master-input, \p MF is never called
  /// if \p Ts is empty.
  ///
  /// \return trigger handler function based on \p MF
  ///
  /// \pre Statically, the indices match the elements: \code
  /// sizeof...(Ts) == sizeof...(S0)
  /// \endcode Dynamically, \p Ts... match \c
  /// rosa::deluxe::DeluxeSensor::MasterInputType: \code
  /// MasterInputType == DeluxeTuple<Ts...>::TT
  /// \endcode
  template <typename... Ts, size_t... S0>
  H triggerHandlerFromProcessingFunction(
      std::function<void(std::pair<DeluxeTuple<Ts...>, bool>)> &&MF,
      Seq<S0...>) noexcept;

  /// Wraps a data source function into a trigger handler.
  ///
  /// \see \c rosa::deluxe::DeluxeSensor::FP, \c
  /// rosa::deluxe::DeluxeSensor::SFP, and \c DeluxeSensorTriggerHandlers
  ///
  /// \tparam T type of data provided by \p F
  ///
  /// \param F function to generate value with
  /// \param inSimulation if F is a data source for Simulation
  ///
  /// \return trigger handler function based on \p F
  ///
  /// \pre Statically, the type agument \p T is an instance of \c
  /// rosa::deluxe::DeluxeTuple: \code
  /// IsDeluxeTuple<T>::Value
  /// \endcode Dynamically, \p T matches \c
  /// rosa::deluxe::DeluxeSensor::OutputType: \code
  /// OutputType == T::TT
  /// \endcode
  template <typename T>
  H triggerHandlerFromDataSource(std::function<T(void)> &&F,
                                 bool inSimulation) noexcept;

public:
  /// Creates a new instance.
  ///
  /// The constructor instantiates the base-class with functions to handle
  /// messages as defined for the *deluxe interface*.
  ///
  /// \todo Enforce \p F and \p MF do not potentially throw exception.
  ///
  /// \tparam MT type of master-input handled by \p MF
  /// \tparam T type of data to operate on
  ///
  /// \note Instantiation fails if any of the type arguments \p MT and \p T is
  /// not an instance of \c rosa::deluxe::DeluxeTuple or \p T is \c
  /// rosa::deluxe::EmptyDeluxeTuple.
  ///
  /// \note If \p MT is \c rosa::deluxe::EmptyDeluxeTuple, the constructed
  /// object does not receive master-input.
  ///
  /// \param Kind kind of the new \c rosa::Unit instance
  /// \param Id unique identifier of the new \c rosa::Unit instance
  /// \param Name name of the new \c rosa::Unit instance
  /// \param S \c rosa::MessagingSystem owning the new instance
  /// \param MF function to process master-input values with
  /// \param F function to generate the next value with during normal operation
  ///
  /// \pre Statically, \p MT and \p T are instances of \c
  /// rosa::deluxe::DeluxeTuple and \p T contains at least one element:\code
  /// TypeListAllDeluxeTuple<TypeList<MT, T>>::Value && T::Length > 0
  /// \endcode
  /// Dynamically, the instance is created as of kind
  /// \c rosa::deluxe::atoms::SensorKind:
  /// \code
  /// Kind == rosa::deluxe::atoms::SensorKind
  /// \endcode
  ///
  /// \see \c rosa::deluxe::DeluxeTuple
  template <
      typename MT, typename T,
      typename = std::enable_if_t<
          TypeListAllDeluxeTuple<TypeList<MT, T>>::Value && (T::Length > 0)>>
  DeluxeSensor(const AtomValue Kind, const id_t Id, const std::string &Name,
               MessagingSystem &S,
               std::function<void(std::pair<MT, bool>)> &&MF,
               std::function<T(void)> &&F) noexcept;

  /// Destroys \p this object.
  ~DeluxeSensor(void) noexcept;

  /// Returns the current execution policy of \p this object.
  ///
  /// \see \c rosa::deluxe::DeluxeExecutionPolicy
  ///
  /// \note The returned reference is valid only as long as \c
  /// rosa::deluxe::DeluxeSensor::setExecutionPolicy() is not called and \p this
  /// object is not destroyed.
  ///
  /// \return \c rosa::deluxe::DeluxeSensor::ExecutionPolicy
  const DeluxeExecutionPolicy &executionPolicy(void) const noexcept;

  /// Sets the current execution policy of \p this object to \p EP.
  ///
  /// \see \c rosa::deluxe::DeluxeExecutionPolicy
  ///
  /// \note \p EP is set only if it can handle \p this object.
  ///
  /// \param EP the new execution policy for \p this object
  ///
  /// \return if \p EP was successfully set for \p this object.
  bool setExecutionPolicy(std::unique_ptr<DeluxeExecutionPolicy> &&EP) noexcept;

  /// The *master* of \p this object, if any.
  ///
  /// \see \c rosa::deluxe::DeluxeSensor::registerMaster
  ///
  /// \return the *master* registered for \p this object
  Optional<AgentHandle> master(void) const noexcept;

  /// Registers a *master* for \p this object.
  ///
  /// The new *master* is registered by overwriting the reference to any
  /// already registered *master*. One can clear the registered reference by
  /// passing an *empty* \c rosa::Optional object as actual argument.
  ///
  /// \note The role of the referred *master* is validated by checking its
  /// *kind*.
  ///
  /// \note Any call to \c rosa::deluxe::DeluxeSensor::registerMaster should be
  /// paired with a corresponding call of \c
  /// rosa::deluxe::DeluxeAgent::registerSlave, which validates that
  /// input/output types of master and slave matches.
  ///
  /// \param _Master the *master* to register
  ///
  /// \pre \p Master is empty or of kind \c rosa::deluxe::atoms::AgentKind:
  /// \code
  /// !_Master || unwrapAgent(*_Master).Kind == rosa::deluxe::atoms::AgentKind
  /// \endcode
  void registerMaster(const Optional<AgentHandle> _Master) noexcept;

  /// Clears the simulation trigger handler of \p this object.
  ///
  /// The function assigns \c rosa::deluxe::DeluxeSensor::SFP with \c nullptr.
  void clearSimulationDataSource(void) noexcept;

  /// Tells whether a simulation trigger handler is set for \p this object.
  ///
  /// The function returns whether \c rosa::deluxe::DeluxeSensor::SFP is not
  /// \c nullptr.
  ///
  /// \return if a simulation trigger handler is set for \p this object.
  bool simulationDataSourceIsSet(void) const noexcept;

  /// Registers a simulation data source for \p this object.
  ///
  /// A new simulation trigger handler wrapping \p SF is stored in
  /// \c rosa::deluxe::DeluxeSensor::SFP by overwriting any already registered
  /// simulation data source.
  ///
  /// \todo Enforce SF does not potentially throw exception.
  ///
  /// \tparam Ts types of elements of values provided by \p SF
  ///
  /// \param SF function to generate value with
  ///
  /// \pre \p Ts... match \c rosa::deluxe::DeluxeSensor::OutputType: \code
  /// OutputType == TypeToken<Ts...>::Value
  /// \endcode
  template <typename... Ts>
  void registerSimulationDataSource(
      std::function<DeluxeTuple<Ts...>(void)> &&SF) noexcept;

private:
  /// Sends a value to the *master* of \p this object.
  ///
  /// \p Value is getting sent to \c rosa::deluxe::DeluxeSensor::Master if it
  /// contains a valid handle for a \c rosa::deluxe::DeluxeAgent. The function
  /// does nothing otherwise.
  ///
  /// The elements from \p Value are sent one by one in separate messages to the
  /// *master*.
  ///
  /// \tparam Ts types of the elements in \p Value
  /// \tparam S0 indices for accessing elements of \p Value
  ///
  /// \param Value value to send
  ///
  /// \note The second argument provides indices statically as template
  /// arguments \p S0..., so its actual value is ignored.
  ///
  /// \pre Statically, the indices match the elements: \code
  /// sizeof...(Ts) == sizeof...(S0)
  /// \endcode Dynamically, \p Ts match \c
  /// rosa::deluxe::DeluxeSensor::OutputType: \code
  /// OutputType == TypeToken<Ts...>::Value
  /// \endcode
  template <typename... Ts, size_t... S0>
  void sendToMaster(const DeluxeTuple<Ts...> &Value, Seq<S0...>) noexcept;

  /// Handles master-input and generates the next sensory value upon trigger
  /// from the system.
  ///
  /// Executes \c rosa::deluxe::DeluxeSensor::MFP for processing master-input
  /// and data generating function \c rosa::deluxe::DeluxeSensor::FP or \c
  /// rosa::deluxe::DeluxeSensor::SFP if set.
  ///
  /// \note The only argument is a \c rosa::AtomConstant, hence its actual
  /// value is ignored.
  ///
  /// \pre Master-input is supposed to be completely received upon triggering:
  /// \code
  /// MasterInputNextPos == 0
  /// \endcode
  void handleTrigger(atoms::Trigger) noexcept;

  /// Stores a new input value from the *master*.
  ///
  /// The function stores \p Value at position \p Pos in \c
  /// rosa::deluxe::DeluxeSensor::MasterInputValue and also sets the
  /// flag \c rosa::deluxe::DeluxeSensor::MasterInputChanged. The function also
  /// takes care of checking and updating \c
  /// rosa::deluxe::DeluxeSensor::MasterInputNextPos: increments its value and
  /// resets it to `0` when the last element is received.
  ///
  /// \note Utilized by member functions of group \c
  /// DeluxeSensorMasterInputHandlers.
  ///
  /// \tparam T type of input to store
  ///
  /// \param Id unique identifier of the *master*
  /// \param Pos position of the value in the \c rosa::deluxe::DeluxeTuple
  /// \param Value the input value to store
  ///
  /// \pre The *master* with \p Id is registered, \p Pos is the expected
  /// position of master-input, and the input from the *master* at position \p
  /// Pos is expected to be of type \p T: \code
  /// Master && masterId() == Id && Pos == MasterInputNextPos &&
  /// typeAtPositionOfToken(MasterInputType, Pos) == TypeNumberOf<T>::Value
  /// \endcode
  template <typename T>
  void saveMasterInput(id_t Id, token_size_t Pos, T Value) noexcept;

  /// \defgroup DeluxeSensorMasterInputHandlers Master-input handlers of
  /// rosa::deluxe::DeluxeSensor
  ///
  /// Definition of member functions handling messages from the *master* with
  /// different types of input
  ///
  /// A *slave* generally needs to be prepared to deal with values of any
  /// built-in type to handle messages from its *master*. Each type requires a
  /// separate message handler, which are implemented by these functions. The
  /// functions instantiate \c rosa::deluxe::DeluxeSensor::saveMasterInput with
  /// the proper template argument and pass the content of the message on for
  /// processing.
  ///
  /// \note The member functions in this group are defined by \c
  /// DSMASTERHANDLERDEF.
  ///
  /// \note Keep these definitions in sync with \c rosa::BuiltinTypes.
  ///
  ///@{

  DSMASTERHANDLERDEF(AtomValue)
  DSMASTERHANDLERDEF(int16_t)
  DSMASTERHANDLERDEF(int32_t)
  DSMASTERHANDLERDEF(int64_t)
  DSMASTERHANDLERDEF(int8_t)
  DSMASTERHANDLERDEFN(long double, long_double)
  DSMASTERHANDLERDEFN(std::string, std__string)
  DSMASTERHANDLERDEF(uint16_t)
  DSMASTERHANDLERDEF(uint32_t)
  DSMASTERHANDLERDEF(uint64_t)
  DSMASTERHANDLERDEF(uint8_t)
  DSMASTERHANDLERDEF(unit_t)
  DSMASTERHANDLERDEF(bool)
  DSMASTERHANDLERDEF(double)
  DSMASTERHANDLERDEF(float)

  /// @}
};

template <typename... Ts, size_t... S0>
DeluxeSensor::H DeluxeSensor::triggerHandlerFromProcessingFunction(
    std::function<void(std::pair<DeluxeTuple<Ts...>, bool>)> &&MF,
    Seq<S0...>) noexcept {
  using MT = DeluxeTuple<Ts...>;
  STATIC_ASSERT(sizeof...(Ts) == sizeof...(S0), "inconsistent arguments");
  ASSERT(MasterInputType == MT::TT);

  // NOTE: Clang 6 warns about unused lambda captures; we suppress that
  // warning (those variables need to be captured).
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-lambda-capture"
#endif // defined __clang__
  return [ this, MF ](void) noexcept {
    // Do not do anything for master-input type \c
    // rosa::deluxe::EmptyDeluxeTuple.
    if constexpr (!std::is_same<MT, EmptyDeluxeTuple>::value) {
      LOG_TRACE_STREAM << "DeluxeSensor " << FullName
                       << " handles master-input." << std::endl;
      // The assert must hold if \p this object was successfuuly constructed.
      ASSERT((true && ... &&
              (static_cast<size_t>(static_cast<token_size_t>(S0)) == S0)));
      const auto MasterInputArg = std::make_pair(
          // Get all elements of the tuple in a fold expression.
          DeluxeTuple<Ts...>(*static_cast<const Ts *>(
              MasterInputValue->pointerTo(static_cast<token_size_t>(S0)))...),
          MasterInputChanged);
      MasterInputChanged = false;
      MF(MasterInputArg);
    }
  };
#ifdef __clang__
#pragma clang diagnostic pop
#endif // defined __clang__
}

template <typename T>
DeluxeSensor::H
DeluxeSensor::triggerHandlerFromDataSource(std::function<T(void)> &&F,
                                           bool inSimulation) noexcept {
  STATIC_ASSERT(IsDeluxeTuple<T>::Value, "not tuple type argument");
  ASSERT(OutputType == T::TT);
  return [ this, F, inSimulation ](void) noexcept {
    // Get value and send it to master only if \p ExecutionPolicy allows it.
    if (ExecutionPolicy->shouldProcess({})) {
      LOG_TRACE_STREAM << "DeluxeSensor " << Name << " obtains next value."
                       << std::endl;
      sendToMaster(F(), seq_t<T::Length>());
    } else {
      LOG_TRACE_STREAM << "DeluxeSensor " << Name << " skips next value."
                       << std::endl;
      if (inSimulation) {
        // But read input value in Simulation anyway as input values are
        // provided for the highest execution frequency for simulation
        (void)F();
      }
    }
  };
}

template <typename MT, typename T, typename>
DeluxeSensor::DeluxeSensor(const AtomValue Kind, const id_t Id,
                           const std::string &Name, MessagingSystem &S,
                           std::function<void(std::pair<MT, bool>)> &&MF,
                           std::function<T(void)> &&F) noexcept
    : Agent(Kind, Id, Name, S, THISMEMBER(handleTrigger),
            DSMASTERHANDLERREF(AtomValue), DSMASTERHANDLERREF(int16_t),
            DSMASTERHANDLERREF(int32_t), DSMASTERHANDLERREF(int64_t),
            DSMASTERHANDLERREF(int8_t), DSMASTERHANDLERREF(long_double),
            DSMASTERHANDLERREF(std__string), DSMASTERHANDLERREF(uint16_t),
            DSMASTERHANDLERREF(uint32_t), DSMASTERHANDLERREF(uint64_t),
            DSMASTERHANDLERREF(uint8_t), DSMASTERHANDLERREF(unit_t),
            DSMASTERHANDLERREF(bool), DSMASTERHANDLERREF(double),
            DSMASTERHANDLERREF(float)),
      ExecutionPolicy(DeluxeExecutionPolicy::decimation(1)), OutputType(T::TT),
      MasterInputType(MT::TT), MasterInputNextPos(0), MasterInputChanged(false),
      MasterInputValue(new typename TokenizedStorageForTypeList<
                       typename UnwrapDeluxeTuple<MT>::Type>::Type()),
      MFP(triggerHandlerFromProcessingFunction(std::move(MF),
                                               seq_t<MT::Length>())),
      FP(triggerHandlerFromDataSource(std::move(F), false)), SFP(nullptr) {
  ASSERT(Kind == atoms::SensorKind);
  LOG_TRACE_STREAM << "DeluxeSensor " << FullName << " is created."
                   << std::endl;
  ASSERT(inv());
}

template <typename... Ts>
void DeluxeSensor::registerSimulationDataSource(
    std::function<DeluxeTuple<Ts...>(void)> &&SF) noexcept {
  ASSERT(OutputType == TypeToken<Ts...>::Value);
  SFP = triggerHandlerFromDataSource(std::move(SF), true);
  ASSERT(inv());
}

template <typename... Ts, size_t... S0>
void DeluxeSensor::sendToMaster(const DeluxeTuple<Ts...> &Value,
                                Seq<S0...>) noexcept {
  STATIC_ASSERT(sizeof...(Ts) == sizeof...(S0), "inconsistent arguments");
  ASSERT(OutputType == TypeToken<Ts...>::Value);

  // The assert must hold if \p this object was successfuuly constructed.
  ASSERT((true && ... &&
          (static_cast<size_t>(static_cast<token_size_t>(S0)) == S0)));
  // Create a static constant array for these indices to be available as lvalue
  // references when creating messages below. \c S0... when used directly in a
  // fold expression is a temporary value, which would result in \c
  // rosa::Message instances being created with rvalue references. Further, all
  // other values would to copied into a temporary variable for making them
  /// available as rvalue references (they are constant lvalue references here).
  static constexpr std::array<token_size_t, sizeof...(S0)> Indices{{S0...}};

  LOG_TRACE_STREAM << "DeluxeSensor " << FullName << "(" << Id
                   << ") sends to master("
                   << static_cast<bool>(Master && *Master) << "): " << Value
                   << std::endl;

  // There is a handle and the referred *master* is in a valid state.
  if (Master && *Master) {
    // Handle each element of the tuple in a fold expression.
    (Master->sendMessage(Message::create(atoms::Slave::Value, Id, Indices[S0],
                                         std::get<S0>(Value))),
     ...);
  }
  ASSERT(inv());
}

template <typename T>
void DeluxeSensor::saveMasterInput(id_t Id, token_size_t Pos,
                                   T Value) noexcept {
  ASSERT(Master && masterId() == Id && Pos == MasterInputNextPos &&
         typeAtPositionOfToken(MasterInputType, Pos) == TypeNumberOf<T>::Value);

  LOG_TRACE_STREAM << "DeluxeSensor " << FullName << "(" << Id
                   << ") saves value from master: (" << static_cast<size_t>(Pos)
                   << ") " << Value << std::endl;

  // Save value.
  *static_cast<T *>(MasterInputValue->pointerTo(Pos)) = Value;

  // Update position of next value.
  if (++MasterInputNextPos == lengthOfToken(MasterInputType)) {
    MasterInputNextPos = 0;
  }

  // Set flag.
  MasterInputChanged = true;
}

} // End namespace deluxe
} // End namespace rosa

#undef DSMASTERHANDLEREF
#undef DSMASTERHANDLEDEF
#undef DSMASTERHANDLEDEFN
#undef DSMASTERHANDLENAME

#endif // ROSA_DELUXE_DELUXESENSOR_HPP
