//===-- rosa/deluxe/DeluxeAgent.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/DeluxeAgent.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Specialization of \c rosa::Agent for *agent* role of the *deluxe
/// interface*.
///
/// \see \c rosa::deluxe::DeluxeContext
///
//===----------------------------------------------------------------------===//

#ifndef ROSA_DELUXE_DELUXEAGENT_HPP
#define ROSA_DELUXE_DELUXEAGENT_HPP

#include "rosa/core/Agent.hpp"

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

#include <map>

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

/// Creates function name for member functions in \c rosa::deluxe::DeluxeAgent.
///
/// \param N name suffix to use
#define DASLAVEHANDLERNAME(N) handleSlave_##N

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

/// Defines member functions for handling messages from *slaves* in
/// \c rosa::deluxe::DeluxeAgent.
///
/// \see \c DeluxeAgentInputHandlers
///
/// \note No pre- and post-conditions are validated directly by these functions,
/// they rather rely on \c rosa::deluxe::DeluxeAgent::saveInput to do that.
///
/// \param T the type of input to handle
/// \param N name suffix for the function identifier
#define DASLAVEHANDLERDEFN(T, N)                                               \
  void DASLAVEHANDLERNAME(N)(atoms::Slave, id_t SlaveId, token_size_t Pos,     \
                             T Value) noexcept {                               \
    saveInput(SlaveId, Pos, Value);                                            \
  }

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

/// Convenience macro for \c DASLAVEHANDLERDEFN with identical arguments.
///
/// \see \c DASLAVEHANDLERDEFN
///
/// This macro can be used instead of \c DASLAVEHANDLERDEFN 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 DASLAVEHANDLERDEF(T) DASLAVEHANDLERDEFN(T, T)

/// Convenience macro for \c DAMASTERHANDLERDEFN with identical arguments.
///
/// \see \c DAMASTERHANDLERDEFN
///
/// This macro can be used instead of \c DAMASTERHANDLERDEFN 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 DAMASTERHANDLERDEF(T) DAMASTERHANDLERDEFN(T, T)

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

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

///@}

namespace rosa {
namespace deluxe {

/// Specialization of \c rosa::Agent for *agent* role of the *deluxe interface*.
///
/// \see \c rosa::deluxe::DeluxeContext
///
/// \invariant There is a compatible *execution policy* set, all input-related
/// container objects have a size matching \c
/// rosa::deluxe::DeluxeAgent::NumberOfInputs, thus having a corresponding entry
/// for each input. \c rosa::deluxe::DeluxeAgent::NumberOfMasterOutputs matches
/// \c rosa::deluxe::DeluxeAgent::NumberOfInputs. All master-output-related
/// container objects have a size matching \c
/// rosa::deluxe::DeluxeAgent::NumberOfMasterOutputs. Types and type-related
/// information of input and master-output values are consistent throughout all
/// the input-related and master-output-related containers, respectively. The
/// actual values in \c rosa::deluxe::DeluxeAgent::InputNextPos and \c
/// rosa::deluxe::DeluxeAgent::MasterInputNextPos are valid with respect to the
/// corresponding types. No *slave* is registered at more than one input
/// position. *Slave* registrations and corresponding reverse lookup
/// information are consistent.
///
/// \see Definition of \c rosa::deluxe::DeluxeAgent::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 DeluxeAgent : public Agent {
  /// Checks whether \p this object holds the class invariant.
  ///
  /// \see Invariant of the class \c rosa::deluxe::DeluxeAgent
  ///
  /// \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::DeluxeAgent::master
  const Token OutputType;

  /// Number of inputs processed by \p this object.
  const size_t NumberOfInputs;

  /// 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::DeluxeAgent::master
  const Token MasterInputType;

  /// Number of outputs produces by \p this object for its *slaves*.
  ///
  /// \note This values is equal to \c
  /// rosa::deluxe::DeluxeAgent::NumberOfInputs.
  ///
  /// \see \c rosa::deluxe::DeluxeAgent::slave.
  const size_t NumberOfMasterOutputs;

private:
  /// Types of input values produced by *slaves* of \p this object.
  ///
  /// \note The \c rosa::Token values stored correspond to \c
  /// rosa::deluxe::DeluxeTuple instances at each argument position. The \c
  /// rosa::TypeNumber values from the stored \c rosa::Token values match the
  /// corresponding values in \c rosa::deluxe::DeluxeAgent::InputValues in
  /// order.
  ///
  /// \note The position of a \c rosa::Token in the \c std::vector indicates
  /// which argument of \p this object's processing function it belongs to. See
  /// also \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
  const std::vector<Token> InputTypes;

  /// Indicates which element of an input is expected from any particular
  /// *slave*.
  ///
  /// The *slave* 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 in the tuple should be received next from
  /// the *slave* at a given position.
  ///
  /// \p this object is supposed to be triggered only when input values has been
  /// received completely, that is all values in the field should hold the value
  /// `0`.
  ///
  /// \see \c rosa::deluxe::DeluxeAgent::handleTrigger
  /// \c rosa::deluxe::DeluxeAgent::saveInput
  std::vector<token_size_t> InputNextPos;

  /// Indicates whether any particular input value has been changed since the
  /// last trigger received from the system.
  ///
  /// All the flags are reset to \c false upon handling a trigger and then set
  /// to \c true by \c rosa::deluxe::DeluxeAgent::saveInput when storing a new
  /// input value in \c rosa::deluxe::DeluxeAgent::InputValues.
  ///
  /// \note The position of a flag in the \c std::vector indicates which
  /// argument of \p this object's processing function it belongs to. See also
  /// \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
  std::vector<bool> InputChanged;

  /// Stores the actual input values.
  ///
  /// \note The types of stored values match the corresponding
  /// \c rosa::TypeNumber values (in \c rosa::Token in order) in \c
  /// rosa::deluxe::DeluxeAgent::InputTypes.
  ///
  /// \note The position of a \c rosa::AbstractTokenizedStorage in the \c
  /// std::vector indicates which argument of \p this object's processing
  /// function the tuple is; and the position of the value in the \c
  /// rosa::AbstractTokenizedStorage indicates which element of that tuple the
  /// value is. See also \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
  const std::vector<std::unique_ptr<AbstractTokenizedStorage>> InputValues;

  /// 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::DeluxeAgent::handleTrigger
  /// \c rosa::deluxe::DeluxeAgent::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::DeluxeAgent::saveMasterInput when storig a new
  /// input value in \c rosa::deluxe::DeluxeAgent::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::DeluxeAgent::MasterInputType.
  const std::unique_ptr<AbstractTokenizedStorage> MasterInputValue;

  /// Types of output values produced by \p this object for its *slaves*.
  ///
  /// That is the types of values \p this object sends to its *slaves* in a \c
  /// rosa::deluxe::DeluxeTuple.
  ///
  /// \note The position of a type in the \c std::vector indicates which
  /// *slave* of \p this object the type belongs to. See also
  /// \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
  const std::vector<Token> MasterOutputTypes;

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

  /// Handles trigger from the system.
  ///
  /// The actual functions processing *slave* and *master* inputs and generating
  /// optional output to *master* and *slaves* are captured in a lambda
  /// expression that is in turn wrapped in a \c std::function object. The
  /// lambda expression calls the master-input processing function with the
  /// actual master-input data and sends its result -- if any -- to *slaves* by
  /// calling \c rosa::deluxe::DeluxeAgent::handleMasterOutputs; then calls the
  /// input processing function with the actual input data and sends its result
  /// -- if any -- to *master* by calling \c
  /// rosa::deluxe::DeluxeAgent::sendToMaster and *slaves* by calling \c
  /// rosa::deluxe::DeluxeAgent::handleMasterOutputs. Also, all the flags stored
  /// in \c rosa::deluxe::DeluxeAgent::InputChanged and \c
  /// rosa::deluxe::DeluxeAgent::MasterInputChanged are reset when the current
  /// values are processed. The function \c
  /// rosa::deluxe::DeluxeAgent::handleTrigger needs only to call the
  /// function object.
  ///
  /// \see \c
  /// rosa::deluxe::DeluxeAgent::triggerHandlerFromProcessingFunctions
  const H FP;

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

  /// The *slaves* sending input to \p this object.
  ///
  /// \note The position of a *slave* in the \c std::vector indicates which
  /// argument of \p this object's processing function it belongs to. See also
  /// \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
  ///
  /// \note *Slaves* are set dynamically, hence it is possible that a
  /// \c rosa::deluxe::DeluxeAgent instance does have input positions without
  /// any *slave* associated to them.
  ///
  /// \note Reverse lookup information is maintained in
  /// \c rosa::deluxe::DeluxeAgent::SlaveIds, which is to be kept in sync with
  /// the *slaves* stored here.
  std::vector<Optional<AgentHandle>> Slaves;

  /// Associates \c rosa::id_t values to corresponding indices of registered
  /// *slaves*.
  ///
  /// \see \c rosa::deluxe::DeluxeAgent::Slaves
  std::map<id_t, size_t> SlaveIds;

  /// 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;

  /// Tells whether types stored in \c rosa::TypeList \p As match the input
  /// types of \p this object.
  ///
  /// \tparam As \c rosa::TypeList containing types to match against values in
  /// \c rosa::deluxe::DeluxeAgent::InputTypes
  ///
  /// \note Instatiation of the template fails if \p As is not \c
  /// rosa::TypeList.
  ///
  /// \return if types in \p As are instances of \c rosa::deluxe::DeluxeTuple
  /// and their types match \c rosa::Token values stored in \c
  /// rosa::deluxe::DeluxeAgent::InputTypes
  template <typename As> bool inputTypesMatch(void) const noexcept;

  /// Tells whether types stored in \c rosa::TypeList \p Ts match the
  /// master-output types of \p this object.
  ///
  /// \tparam Ts \c rosa::TypeList containing types to match against values in
  /// \c rosa::deluxe::DeluxeAgent::MasterOutputTypes
  ///
  /// \note Instatiation of the template fails if \p As is not \c
  /// rosa::TypeList.
  ///
  /// \return if types in \p Ts match \c rosa::Token and in turn \c
  /// rosa::TypeNumber values stored in \c
  /// rosa::deluxe::DeluxeAgent::MasterOutputTypes
  template <typename Ts> bool masterOutputTypesMatch(void) const noexcept;

  /// Gives the current input value for slave position \p Pos.
  ///
  /// \tparam Pos slave position to get input value for
  /// \tparam Ts types of elements of the input value
  /// \tparam S0 indices for accessing elements of the input value
  ///
  /// \note The arguments provide types and indices statically as template
  /// arguments \p Ts... \p S0..., respectively, so their actual values are
  /// ignored.
  ///
  /// \return current input value for slave position \p Pos
  ///
  /// \pre Statically, the provided indices \p S0... match the length of \p
  /// Ts...: \code
  /// sizeof...(Ts) == sizeof...(S0)
  /// \endcode Dynamically, \p Pos is a valid slave position and type arguments
  /// \p Ts... match the corresponding input value: \code
  ///  Pos < NumberOfInputs && DeluxeTuple<Ts...>::TT == InputTypes[Pos]
  /// \endcode
  template <size_t Pos, typename... Ts, size_t... S0>
  DeluxeTuple<Ts...> prepareInputValueAtPos(TypeList<Ts...>, Seq<S0...>) const
      noexcept;

  /// Gives an \c std::tuple containing the current input values and their
  /// change flags so that they can be used for the processing function.
  ///
  /// \tparam As types of the input values
  /// \tparam S0 indices for accessing input values and their change flags
  ///
  /// \note The only argument provides indices statically as template arguments
  /// \p S0..., so its actual value is ignored.
  ///
  /// \return current input values and their change flags prepared for invoking
  /// the processing function with them
  ///
  /// \pre Statically, all type arguments \p As... are instances of \c
  /// rosa::deluxe::DeluxeTuple and the provided indices \p S0... match the
  /// length of \p As...: \code
  /// TypeListAllDeluxeTuple<TypeList<As...>>::Value &&
  /// sizeof...(As) == sizeof...(S0)
  /// \endcode Dynamically, type arguments \p As... match the input types of \p
  /// this object: \code
  /// inputTypesMatch<TypeList<As...>>()
  /// \endcode
  template <typename... As, size_t... S0>
  std::tuple<std::pair<As, bool>...> prepareCurrentInputs(Seq<S0...>) const
      noexcept;

  /// Invokes a processing function matching the input, output, and
  /// master-output types of \p this object with actual arguments provided in a
  /// \c std::tuple.
  ///
  /// \note \p Args providing the actual arguments for \p F is to be created by
  /// \c rosa::deluxe::DeluxeAgent::prepareCurrentInputs.
  ///
  /// \tparam T output type of the processing function
  /// \tparam Ts types of master-output values of the processing function
  /// \tparam As types of inputs for the processing function
  /// \tparam S0 indices starting with `0` for extracting actual arguments from
  /// \p Args
  ///
  /// \param F the processing function to invoke
  /// \param Args the actual arguments to invoke \p F with
  ///
  /// \note The last argument provides indices statically as template arguments
  /// \p S0..., so its actual value is ignored.
  ///
  /// \return the result of \p F for actual arguments \p Args
  ///
  /// \pre The provided sequence of indices \p S0... constitutes a proper
  /// sequence for extracting all actual arguments for
  /// \p F from \p Args: \code
  /// sizeof...(As) == sizeof...(S0)
  /// \endcode
  template <typename T, typename... Ts, typename... As, size_t... S0>
  static std::tuple<Optional<T>, Optional<Ts>...>
  invokeWithTuple(std::function<std::tuple<Optional<T>, Optional<Ts>...>(
                      std::pair<As, bool>...)>
                      F,
                  const std::tuple<std::pair<As, bool>...> Args,
                  Seq<S0...>) noexcept;

  /// Handles a master-output value for a particular *slave* position.
  ///
  /// \p Value is a \c rosa::Optional resulted by a processing function and
  /// contains a master-output value for the *slave* at position \p Pos. The
  /// function takes the master-output value and sends its actual value, if any,
  /// to the corresponding *slave*.
  ///
  /// \note A master-output of type \c rosa::deluxe::EmptyDeluxeTuple indicates
  /// no actual output and hence no message is generated for a position whose
  /// corresponding master-output type is \c rosa::deluxe::EmptyDeluxeTuple.
  ///
  /// \note The function provides position-based implementation for \c
  /// rosa::deluxe::DeluxeAgent::handleMasterOutputs.
  ///
  /// \tparam Pos the position of the master-output to send \p Value for
  /// \tparam Ts types of elements in \p Value
  ///
  /// \param Value \c rosa::deluxe::DeluxeTuple resulted by the processing
  /// function for *slave* position \p Pos
  ///
  /// \pre \p Pos is a valid master-output position and \p Value matches the
  /// master-output type of \p this object at position \p Pos: \code
  /// Pos < NumberOfMasterOutputs &&
  /// DeluxeTuple<Ts...>::TT == MasterOutputTypes[Pos]
  /// \endcode
  template <size_t Pos, typename... Ts>
  void
  handleMasterOutputAtPos(const Optional<DeluxeTuple<Ts...>> &Value) noexcept;

  /// Handles master-output values from \p Output.
  ///
  /// \p Output is a \c std::tuple resulted by a processing function and
  /// contains master-output values starting at position \p Offset. The function
  /// takes master-output values and sends each actual value to the
  /// corresponding *slave*.
  ///
  /// \tparam Offset index of the first master-output value in \p Output
  /// \tparam Ts output types stored in \p Output
  /// \tparam S0 indices starting with `0` for extracting master-output values
  /// from \p Output
  ///
  /// \note Instantiation fails if any of the type arguments \p Ts... starting
  /// at position \p Offset is not an instance of \c rosa::deluxe::DeluxeTuple
  /// or the number of types \p Ts... is not consistent with the other template
  /// arguments.
  ///
  /// \param Output \c std::tuple resulted by a processing function
  ///
  /// \pre Statically, type arguments \p Ts... starting at position \p Offset
  /// are instances of \c rosa::deluxe::DeluxeTuple and the number of types \p
  /// Ts... is consistent with the other template arguments: \code
  /// TypeListAllDeluxeTuple<
  ///   typename TypeListDrop<Offset, TypeList<Ts...>>::Type>::Value &&
  /// sizeof...(Ts) == Offset + sizeof...(S0)
  /// \endcode Dynamically, \p Output matches the master-output types \p this
  /// object was created with and the provided sequence of indices \p S0...
  /// constitues a proper sequence for extracting all master-output values from
  /// \p Output: \code
  /// masterOutputTypesMatch<typename TypeListDrop<Offset,
  ///                                              TypeList<Ts...>>::Type>() &&
  /// sizeof...(S0) == NumberOfMasterOutputs
  /// \endcode
  template <size_t Offset, typename... Ts, size_t... S0>
  void handleMasterOutputs(const std::tuple<Optional<Ts>...> &Output,
                           Seq<S0...>) noexcept;

  /// Wraps processing functions into a trigger handler.
  ///
  /// \see \c rosa::deluxe::DeluxeAgent::FP
  ///
  /// \note The function cannot be const qualified because the lambda
  /// expression defined in it needs to capture \p this object by a non-const
  /// reference
  ///
  /// \tparam MTs types of elements of master-input processed by \p MF
  /// \tparam T type of output
  /// \tparam Ts types of master-output values
  /// \tparam As types of input values
  /// \tparam S0 indices for accessing master-input values
  ///
  /// \note Instantiation fails if any of the type arguments \p T, \p Ts...,
  /// and \p As... is not an instance of \c rosa::deluxe::DeluxeTuple.
  ///
  /// \param MF function processing master-input and generating output
  /// \param F function processing inputs and generating output
  ///
  /// \note The last 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 MTs is empty.
  ///
  /// \return trigger handler function based on \p F and \p MF
  ///
  /// \pre Statically, type arguments \p T, \p Ts..., and \p As... are
  /// instances of \c rosa::deluxe::DeluxeTuple and the indices match
  /// master-input elements: \code
  /// TypeListAllDeluxeTuple<TypeList<T, Ts..., As...>>::Value &&
  /// sizeof...(MTs) == sizeof...(S0)
  /// \endcode Dynamically, template arguments \p MTs..., \p T, \p Ts..., and
  /// \p As... match the corresponding types \p this object was created with:
  /// \code
  /// MasterInputType == DeluxeTuple<MTs...>::TT && OutputType == T::TT &&
  /// inputTypesMatch<TypeList<As...>>() &&
  /// masterOutputTypesMatch<TypeList<Ts...>>()
  /// \endcode
  template <typename... MTs, typename T, typename... Ts, typename... As,
            size_t... S0>
  H triggerHandlerFromProcessingFunctions(
      std::function<std::tuple<Optional<Ts>...>(
          std::pair<DeluxeTuple<MTs...>, bool>)> &&MF,
      std::function<
          std::tuple<Optional<T>, Optional<Ts>...>(std::pair<As, bool>...)> &&F,
      Seq<S0...>) noexcept;

public:
  /// Creates a new instance.
  ///
  /// The constructor instantiates the base-class with functions to handle
  /// messages as defined for the *deluxe interface*.
  ///
  /// The function \p F generates a \c std::tuple of values: the first value is
  /// the output for the *master* and the rest is for the *slaves*. All output
  /// generated by the function is optional as an agent may decide not to output
  /// anything at some situation.
  ///
  /// \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 output of \p F
  /// \tparam Ts type of master-output values of \p F and \p MF
  /// \tparam As types of input values of \p F
  ///
  /// \note Instantiation fails if any of the type arguments \p MT, \p T, \p
  /// Ts..., and \p As... is not an instance of \c rosa::deluxe::DeluxeTuple or
  /// any of \p T and \p As... is \c rosa::deluxe::EmptyDeluxeTuple or the
  /// number of inputs and master-outputs are not equal.
  ///
  /// \note If \p MT is \c rosa::deluxe::EmptyDeluxeTuple, the constructed
  /// object does not receive master-input. Similarly, if any of \p Ts... is \c
  /// rosa::deluxe::EmptyDeluxeTuple, the constructed object does not generated
  /// master-output for the corresponding *slave* position.
  ///
  /// \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 and generate
  /// master-output with
  /// \param F function to process input values and generate output and
  /// master-output with
  ///
  /// \pre Statically, all the type arguments \p MT, \p T, \p Ts..., and \p
  /// As... are instances of \c rosa::deluxe::DeluxeTuple, with \p T and \p
  /// As... containing at least one element, and the number of input and
  /// master-output types are equal: \code
  /// TypeListAllDeluxeTuple<TypeList<MT, T, Ts..., As...>::Value &&
  /// T::Length > 0 && (true && ... && As::Length > 0) &&
  /// sizeof...(Ts) == sizeof...(As)
  ///\endcode
  /// Dynamically, the instance is created as of kind \c
  /// rosa::deluxe::atoms::AgentKind: \code
  /// Kind == rosa::deluxe::atoms::AgentKind
  /// \endcode
  ///
  /// \see \c rosa::deluxe::DeluxeTuple
  template <typename MT, typename T, typename... Ts, typename... As,
            typename = std::enable_if_t<
                TypeListAllDeluxeTuple<TypeList<MT, T, Ts..., As...>>::Value &&
                (T::Length > 0) && (true && ... && (As::Length > 0)) &&
                sizeof...(Ts) == sizeof...(As)>>
  DeluxeAgent(
      const AtomValue Kind, const id_t Id, const std::string &Name,
      MessagingSystem &S,
      std::function<std::tuple<Optional<Ts>...>(std::pair<MT, bool>)> &&MF,
      std::function<std::tuple<Optional<T>, Optional<Ts>...>(
          std::pair<As, bool>...)> &&F) noexcept;

  /// Destroys \p this object.
  ~DeluxeAgent(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::DeluxeAgent::setExecutionPolicy() is not called and \p this
  /// object is not destroyed.
  ///
  /// \return \c rosa::deluxe::DeluxeAgent::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 is registered.
  ///
  /// \see \c rosa::deluxe::DeluxeAgent::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::DeluxeAgent::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;

  /// Tells the types of values consumed from the *slave* at a position.
  ///
  /// That is the type of values \p this object expect to be sent to it in a \c
  /// rosa::deluxe::DeluxeTuple by its *slave* registered at position \p Pos.
  ///
  /// \see \c rosa::deluxe::DeluxeAgent::slave
  ///
  /// \param Pos position of *slave*
  ///
  /// \return \c rosa::Token representing the types of values consumed from
  /// the *slave* at position \p Pos
  ///
  /// \pre \p Pos is a valid index of input: \code
  /// Pos < NumberOfInputs
  /// \endcode
  Token inputType(const size_t Pos) const noexcept;

  /// Tells the types of values produced for the *slave* at a position.
  ///
  /// That is the types of values \p this object potentially sends in a \c
  /// rosa::deluxe::DeluxeTuple to its *slave* registered at position \p Pos.
  ///
  /// \see \c rosa::deluxe::DeluxeAgent::slave
  ///
  /// \param Pos position of *slave*
  ///
  /// \return \c rosa::Token representing the types of values produced for
  /// the *slave* at position \p Pos
  ///
  /// \pre \p Pos is a valid index of input: \code
  /// Pos < NumberOfMasterOutputs
  /// \endcode
  Token masterOutputType(const size_t Pos) const noexcept;

  /// The *slave* of \p this object registered at a position, if any.
  ///
  /// \see \c rosa::deluxe::DeluxeAgent::registerSlave
  ///
  /// \param Pos position of *slave*
  ///
  /// \return the *slave* registered for \p this object at position \p Pos
  ///
  /// \pre \p Pos is a valid index of input: \code
  /// Pos < NumberOfInputs
  /// \endcode
  Optional<AgentHandle> slave(const size_t Pos) const noexcept;

  /// Registers a *slave* for \p this object at a position.
  ///
  /// The new *slave* is registered by overwriting the reference to any already
  /// registered *slave* at position \p Pos. One can clear the registered
  /// reference by passing an *empty* \c rosa::Optional object as actual
  /// argument. If \p Slave is already registered for another position, the
  /// other position gets cleared.
  ///
  /// \note The role of the referred *slave* is validated by checking its
  /// *kind*.
  ///
  /// \note The type of values produced by the referred *slave* is validated by
  /// matching its `OutputType` against the corresponding value in
  /// \c rosa::deluxe::DeluxeAgent::InputTypes.
  ///
  /// \note The type of master-input values processed by the referred *slave* is
  /// validated by matching its `MasterInputType` against the corresponding
  /// value in \c rosa::deluxe::DeluxeAgent::MasterOutputTypes.
  ///
  /// \param Pos position to register \p Slave at
  /// \param Slave the *slave* to register
  ///
  /// \pre \p Pos is a valid index of input, \p Slave is empty or of kind
  /// \c rosa::deluxe::atoms::AgentKind or \c rosa::deluxe::atoms::SensorKind,
  /// and \p Slave -- if not empty -- produces values of types matching the
  /// expected input type at position \p Pos and processes values of types
  /// matching the produced master-output type at position \p Pos:
  /// \code
  /// Pos < NumberOfInputs &&
  /// (!Slave ||
  /// (unwrapAgent(*Slave.)Kind == rosa::deluxe::atoms::SensorKind &&
  ///  static_cast<const DeluxeSensor &>(unwrapAgent(*Slave)).OutputType ==
  ///  InputTypes[Pos] &&
  ///  (emptyToken(MasterOutputTypes[Pos]) ||
  ///   static_cast<const DeluxeSensor &>(unwrapAgent(*Slave)).MasterInputType
  ///   == MasterOutputTypes[Pos])) ||
  /// (unwrapAgent(*Slave).Kind == rosa::deluxe::atoms::AgentKind &&
  ///  static_cast<const DeluxeAgent &>(unwrapAgent(*Slave)).OutputType ==
  ///  InputTypes[Pos] &&
  ///  (emptyToken(MasterOutputTypes[Pos]) ||
  ///   static_cast<const DeluxeAgent &>(unwrapAgent(*Slave)).MasterInputType ==
  ///   MasterOutputTypes[Pos])))
  /// \endcode
  void registerSlave(const size_t Pos,
                     const Optional<AgentHandle> Slave) noexcept;

  /// Tells the position of a registered *slave*.
  ///
  /// \param Slave \c rosa::AgentHandle for the *slave* to check
  ///
  /// \return position of \p Slave if it is registered and found,
  /// \c rosa::deluxe::DeluxeAgent::NumberOfInputs otherwise.
  size_t positionOfSlave(AgentHandle Slave) const noexcept;

private:
  /// Sends a value to the *master* of \p this object.
  ///
  /// \p Value is getting sent to \c rosa::deluxe::DeluxeAgent::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::DeluxeiAgent::OutputType: \code
  /// OutputType == TypeToken<Ts...>::Value
  /// \endcode
  template <typename... Ts, size_t... S0>
  void sendToMaster(const DeluxeTuple<Ts...> &Value, Seq<S0...>) noexcept;

  /// Sends a value to a *slave* of \p this object at position \p Pos.
  ///
  /// \p Value is getting sent to \c rosa::deluxe::DeluxeAgent::Slaves[Pos] if
  /// it contains a valid handle. The function does nothing otherwise.
  ///
  /// The elements from \p Value are sent one by one in separate messages to the
  /// *slave*.
  ///
  /// \tparam Ts types of the elements in \p Value
  /// \tparam S0 indices for accessing elements of \p Value
  ///
  /// \param Pos the position of the *slave* to send \p Value to
  /// \param Value value to send
  ///
  /// \pre Statically, the indices match the elements: \code
  /// sizeof...(Ts) == sizeof...(S0)
  /// \endcode Dynamically, \p Pos is a valid *slave* position and \p Ts match
  /// \c rosa::deluxe::DeluxeiAgent::MasterOutputTypes[Pos]: \code
  /// Pos < NumberOfMasterOutputs &&
  /// MasterOutputTypes[Pos] == TypeToken<Ts...>::Value
  /// \endcode
  template <typename... Ts, size_t... S0>
  void sendToSlave(const size_t Pos, const DeluxeTuple<Ts...> &Value,
                   Seq<S0...>) noexcept;

  /// Generates the next output by processing current input values upon trigger
  /// from the system.
  ///
  /// Executes \c rosa::deluxe::DeluxeAgent::FP.
  ///
  /// \note The only argument is a \c rosa::AtomConstant, hence its actual
  /// value is ignored.
  ///
  /// \pre Master-input and all input from *slaves* are supposed to be
  /// completely received upon triggering: \code
  /// MasterInputNextPos == 0 &&
  /// std::all_of(InputNextPos.begin(), InputNextPos.end(),
  ///             [](const token_size_t &I){return I == 0;})
  /// \endcode
  void handleTrigger(atoms::Trigger) noexcept;

  /// Stores a new input value from a *slave*.
  ///
  /// The function stores \p Value at position \p Pos in \c
  /// rosa::deluxe::DeluxeAgent::InputValues at the position associated to \p Id
  /// in \c rosa::deluxe::DeluxeAgent::SlaveIds and also sets the corresponding
  /// flag in \c rosa::deluxe::DeluxeAgent::InputChanged. The function also
  /// takes care of checking and updating \c
  /// rosa::deluxe::DeluxeSensor::MasterInputNextPos at the corresponding
  /// position: increments the value and resets it to `0` when the last element
  /// is received.
  ///
  /// \note Utilized by member functions of group \c DeluxeAgentInputHandlers.
  ///
  /// \tparam T type of input to store
  ///
  /// \param Id unique identifier of *slave*
  /// \param Pos position of the value in the \c rosa::deluxe::DeluxeTuple
  /// \param Value the input value to store
  ///
  /// \pre The *slave* with \p Id is registered, \p Pos is the expected
  /// position of input from the *slave*, and the input from it is expected to
  /// be of type \p T: \code
  /// SlaveIds.find(Id) != SlaveIds.end() &&
  /// Pos == InputNextPos[SlaveIds.find(Id)->second] &&
  /// typeAtPositionOfToken(InputTypes[SlaveIds.find(Id)->second], Pos) ==
  /// TypeNumberOf<T>::Value
  /// \endcode
  template <typename T>
  void saveInput(id_t Id, token_size_t Pos, T Value) noexcept;

  /// Stores a new input value from the *master*.
  ///
  /// The function stores \p Value at position \p Pos in \c
  /// rosa::deluxe::DeluxeAgent::MasterInputValue and also sets the
  /// flag \c rosa::deluxe::DeluxeAgent::MasterInputChanged. The function also
  /// takes care of checking and updating \c
  /// rosa::deluxe::DeluxeAgent::MasterInputNextPos: increments its value and
  /// reset to `0` when the last element is received.
  ///
  /// \note Utilized by member functions of group \c
  /// DeluxeAgentMasterInputHandlers.
  ///
  /// \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 DeluxeAgentInputHandlers Input handlers of
  /// rosa::deluxe::DeluxeAgent
  ///
  /// Definition of member functions handling messages from *slaves* with
  /// different types of input
  ///
  /// A *master* generally needs to be prepared to deal with values of any
  /// built-in type to handle messages from its *slaves*. Each type requires a
  /// separate message handler, which are implemented by these functions. The
  /// functions instantiate \c rosa::deluxe::DeluxeAgent::saveInput 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
  /// DASLAVEHANDLERDEF.
  ///
  /// \note Keep these definitions in sync with \c rosa::BuiltinTypes.
  ///
  ///@{

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

  /// @}

  /// \defgroup DeluxeAgentMasterInputHandlers Master-input handlers of
  /// rosa::deluxe::DeluxeAgent
  ///
  /// 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::DeluxeAgent::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
  /// DAMASTERHANDLERDEF.
  ///
  /// \note Keep these definitions in sync with \c rosa::BuiltinTypes.
  ///
  ///@{

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

  /// @}
};

/// Anonymous namespace with implementation for \c
/// rosa::deluxe::DeluxeAgent::DeluxeAgent, \c
/// rosa::deluxe::DeluxeAgent::inputTypesMatch, and \c
/// rosa::deluxe::DeluxeAgent::masterOutputTypesMatch, consider it private.
namespace {

/// Creates storages for data of types \p Ts... in a \c std::vector of \c
/// rosa::TokenizedStorage.
///
/// \note Utilized by \c rosa::deluxe::DeluxeAgnet::DeluxeAgent to initialize \c
/// rosa::deluxe::DeluxeAgent::InputValues. That is due to not being able to use
/// an initializer list directly; the initializer list always copies but \c
/// std::unique_ptr is not copyable.
///
/// \tparam Ts types to create storages for
///
/// \note Instantiation fails if any of the type arguments \p Ts... is not an
/// instance of \c rosa::deluxe::DeluxeTuple.
///
/// \return \c std::vector with pointers for the created storage objects
///
/// \pre Statically, all the type arguments \p Ts... are instances of \c
/// rosa::deluxe::DeluxeTuple: \code
/// TypeListAllDeluxeTuple<TypeList<Ts...>>::Value
/// \endcode
template <typename... Ts>
std::vector<std::unique_ptr<AbstractTokenizedStorage>>
makeInputStorages(void) noexcept {
  std::vector<std::unique_ptr<AbstractTokenizedStorage>> InputStorages;
  (InputStorages.push_back(
       std::make_unique<typename TokenizedStorageForTypeList<
           typename UnwrapDeluxeTuple<Ts>::Type>::Type>()),
   ...);
  return InputStorages;
}

/// Template \c struct whose specializations provide a recursive implementation
/// for \c TypesMatchList.
///
/// \tparam As types to match
template <typename... As> struct TypesMatchImpl;

/// Template specialization for the case, when at least one type is to
/// be matched and that is an instance of \c rosa::deluxe::DeluxeTuple.
///
/// \tparam Ts types of elements in the \c rosa::deluxe::DeluxeTuple to match
/// \tparam As further types to match
template <typename... Ts, typename... As>
struct TypesMatchImpl<DeluxeTuple<Ts...>, As...> {
  /// Tells whether types \c rosa::deluxe::DeluxeTuple<Ts...> and \p As... match
  /// \c rosa::Token values stored in \p Tokens starting at position \p Pos.
  ///
  /// The function has got a recursive implementation: it matches the first
  /// type \c rosa::deluxe::DeluxeTuple<Ts...> against \c rosa::Token at
  /// position \p Pos of \p Tokens, then further types \p As... are matched
  /// recursively starting at position \c (Pos + 1).
  ///
  /// \param Tokens container of \c rosa::Token values to match types against
  /// \param Pos position in \p Tokens to start matching at
  ///
  /// \return if types \c rosa::deluxe::DeluxeTuple<Ts...> and \p As... match \c
  /// rosa::Token values stored in \p Tokens starting at position \p Pos
  static bool f(const std::vector<Token> &Tokens, size_t Pos) noexcept {
    return Pos < Tokens.size() && TypeToken<Ts...>::Value == Tokens[Pos] &&
           TypesMatchImpl<As...>::f(Tokens, Pos + 1);
  }
};

/// Template specialization for the case, when at least one type is to
/// be matched and that is *not* an instance of \c rosa::deluxe::DeluxeTuple.
///
/// \tparam T first type to match
/// \tparam As further types to match
template <typename T, typename... As> struct TypesMatchImpl<T, As...> {
  /// Tells whether types \p T and \p As... match \c rosa::Token values stored
  /// in \p Tokens starting at position \p Pos.
  ///
  /// This specialization is used only when \p T is not an instance of \c
  /// rosa::deluxe::DeluxeTuple, in which case the match is not successful.
  ///
  /// \note The function takes two parameters to match the general signature but
  /// the actual values are ignored.
  ///
  /// \return `false`
  static bool f(const std::vector<Token> &, size_t) noexcept { return false; }
};

/// Template specialization for the terminal case, when no type remains to
/// check.
template <> struct TypesMatchImpl<> {
  /// Tells whether \p Pos is the number of values stored in \p Tokens.
  ///
  /// In this terminal case, there is no more types to match because all the
  /// types are supposed to be already matched successfully. The whole list of
  /// types already matched is a complete match if it covers all values in
  /// \p Tokens. That is true if \p Pos points exactly to the end of \p Tokens.
  ///
  /// \param Tokens container of \c rosa::Token values to match types against
  /// \param Pos position in \p Tokens to start matching at
  ///
  /// \return if \p Pos is the number of values stored in \p Tokens
  static bool f(const std::vector<Token> &Tokens, size_t Pos) noexcept {
    return Pos == Tokens.size();
  }
};

/// Template \c struct that provides an implementation for \c
/// rosa::deluxe::DeluxeAgent::inputTypesMatch and \c
/// rosa::deluxe::DeluxeAgent::masterOutputTypesMatch.
///
/// \note Match a list of types \p List against a \c std::vector of
/// \c rosa::Token values, \c Tokens, like \code
/// bool match = TypesMatchList<List>::f(Tokens);
/// \endcode
/// If any type in \c rosa::TypeList \p Listis not an instance of \c
/// rosa::deluxe::DeluxeTuple, the match gives a negative result.
///
/// \tparam List \c rosa::TypeList that contains types to match
template <typename List> struct TypesMatchList;

/// Template specialization implementing the feature.
///
/// \tparam As types to match
template <typename... As> struct TypesMatchList<TypeList<As...>> {
  /// Tells whether types \p As... match \c rosa::Token values stored in \p
  /// Tokens.
  ///
  /// The function unwraps the types from \c rosa::TypeList and utilizes \c
  /// TypesMatchImpl to do the check.
  ///
  /// \param Tokens container of \c rosa::Token values to match types against
  ///
  /// \return if types \p As... match \c rosa::Token values stored in \p Tokens
  static bool f(const std::vector<Token> &Tokens) noexcept {
    return TypesMatchImpl<As...>::f(Tokens, 0);
  }
};

} // End namespace

template <typename As> bool DeluxeAgent::inputTypesMatch(void) const noexcept {
  return TypesMatchList<As>::f(InputTypes);
}

template <typename Ts>
bool DeluxeAgent::masterOutputTypesMatch(void) const noexcept {
  return TypesMatchList<Ts>::f(MasterOutputTypes);
}

template <size_t Pos, typename... Ts, size_t... S0>
DeluxeTuple<Ts...> DeluxeAgent::prepareInputValueAtPos(TypeList<Ts...>,
                                                       Seq<S0...>) const
    noexcept {
  using T = DeluxeTuple<Ts...>;
  STATIC_ASSERT(sizeof...(Ts) == sizeof...(S0), "inconsistent type arguments");
  ASSERT(inv() && Pos < NumberOfInputs && T::TT == InputTypes[Pos]);

  // The below should hold because of the above, just leave it for sanity check.
  STATIC_ASSERT((true && ... &&
                 (static_cast<size_t>(static_cast<token_size_t>(S0)) == S0)),
                "Should not happen");

  const auto &SlaveInput = InputValues[Pos];

  // Get all elements of the tuple in a fold expression.
  return T(*static_cast<const Ts *>(
      SlaveInput->pointerTo(static_cast<token_size_t>(S0)))...);
}

template <typename... As, size_t... S0>
std::tuple<std::pair<As, bool>...>
DeluxeAgent::prepareCurrentInputs(Seq<S0...>) const noexcept {
  STATIC_ASSERT(TypeListAllDeluxeTuple<TypeList<As...>>::Value,
                "not tuple types");
  STATIC_ASSERT(sizeof...(As) == sizeof...(S0), "inconsistent type arguments");
  ASSERT(inv() && inputTypesMatch<TypeList<As...>>());

  return std::make_tuple(std::make_pair(
      prepareInputValueAtPos<S0>(typename UnwrapDeluxeTuple<As>::Type(),
                                 seq_t<As::Length>()),
      InputChanged[S0])...);
}

template <typename T, typename... Ts, typename... As, size_t... S0>
std::tuple<Optional<T>, Optional<Ts>...> DeluxeAgent::invokeWithTuple(
    std::function<
        std::tuple<Optional<T>, Optional<Ts>...>(std::pair<As, bool>...)>
        F,
    const std::tuple<std::pair<As, bool>...> Args, Seq<S0...>) noexcept {
  STATIC_ASSERT(sizeof...(As) == sizeof...(S0),
                "wrong number of type parameters");
  return F(std::get<S0>(Args)...);
}

template <size_t Pos, typename... Ts>
void DeluxeAgent::handleMasterOutputAtPos(
    const Optional<DeluxeTuple<Ts...>> &Value) noexcept {
  using MOT = DeluxeTuple<Ts...>;
  ASSERT(inv() && Pos < NumberOfMasterOutputs &&
         MOT::TT == MasterOutputTypes[Pos]);
  // Do not do anything for master-output of type \c
  // rosa::deluxe::EmptyDeluxeTuple and when \p Value is empty.
  if
    constexpr(!std::is_same<MOT, EmptyDeluxeTuple>::value) {
      if (Value) {
        sendToSlave(Pos, *Value, seq_t<MOT::Length>());
      }
    }
  else {
    (void)Value;
  }
  ASSERT(inv());
}

template <size_t Offset, typename... Ts, size_t... S0>
void DeluxeAgent::handleMasterOutputs(const std::tuple<Optional<Ts>...> &Output,
                                      Seq<S0...>) noexcept {
  using MOTs = typename TypeListDrop<Offset, TypeList<Ts...>>::Type;
  STATIC_ASSERT(TypeListAllDeluxeTuple<MOTs>::Value,
                "not tuple type arguments");
  STATIC_ASSERT(sizeof...(Ts) == Offset + sizeof...(S0),
                "inconsistent arguments");
  ASSERT(inv() && masterOutputTypesMatch<MOTs>() &&
         sizeof...(S0) == NumberOfMasterOutputs);
  // Handle each master-output position in a fold expression.
  (handleMasterOutputAtPos<S0>(std::get<Offset + S0>(Output)), ...);
  ASSERT(inv());
}

template <typename... MTs, typename T, typename... Ts, typename... As,
          size_t... S0>
DeluxeAgent::H DeluxeAgent::triggerHandlerFromProcessingFunctions(
    std::function<
        std::tuple<Optional<Ts>...>(std::pair<DeluxeTuple<MTs...>, bool>)> &&MF,
    std::function<
        std::tuple<Optional<T>, Optional<Ts>...>(std::pair<As, bool>...)> &&F,
    Seq<S0...>) noexcept {
  using MT = DeluxeTuple<MTs...>;
  STATIC_ASSERT((TypeListAllDeluxeTuple<TypeList<T, Ts..., As...>>::Value),
                "not tuple type arguments");
  STATIC_ASSERT(sizeof...(MTs) == sizeof...(S0), "inconsistent arguments");
  ASSERT(MasterInputType == MT::TT && OutputType == T::TT &&
         inputTypesMatch<TypeList<As...>>() &&
         masterOutputTypesMatch<TypeList<Ts...>>());

  return [ this, MF, F ]() noexcept {
    // \note These indices work for both inputs and master-outputs.
    using SlaveIndices = seq_t<sizeof...(As)>;

    // Handle master-input.
    // Do not do anything for master-input type \c
    // rosa::deluxe::EmptyDeluxeTuple.
    if (!std::is_same<MT, EmptyDeluxeTuple>::value) {
      LOG_TRACE_STREAM << "DeluxeAgent " << FullName << " handles master-input."
                       << std::endl;
      // The assert must hold if \p this object was successfully constructed.
      STATIC_ASSERT((true && ... && (static_cast<size_t>(
                                         static_cast<token_size_t>(S0)) == S0)),
                    "Unexpected error");
      const auto MasterInputArg = std::make_pair(
          // Get all elements of the tuple in a fold expression.
          MT(*static_cast<const MTs *>(
              MasterInputValue->pointerTo(static_cast<token_size_t>(S0)))...),
          MasterInputChanged);
      MasterInputChanged = false;
      const std::tuple<Optional<Ts>...> MasterOutput = MF(MasterInputArg);
      handleMasterOutputs<0>(MasterOutput, SlaveIndices());
    }

    // Handle inputs.
    // Call the processing function only if \p ExecutionPolicy allows.
    if (ExecutionPolicy->shouldProcess(InputChanged)) {
      LOG_TRACE_STREAM << "DeluxeAgent " << FullName << " handles input."
                       << std::endl;
      const auto InputArgs = prepareCurrentInputs<As...>(SlaveIndices());
      std::fill(InputChanged.begin(), InputChanged.end(), false);
      const std::tuple<Optional<T>, Optional<Ts>...> Output =
          invokeWithTuple(F, InputArgs, SlaveIndices());
      const auto OutputToMaster = std::get<0>(Output);
      if (OutputToMaster) {
        sendToMaster(*OutputToMaster, seq_t<T::Length>());
      }
      handleMasterOutputs<1>(Output, SlaveIndices());
    } else {
      LOG_TRACE_STREAM << "DeluxeAgent " << Name << " skips input."
                       << std::endl;
    }
  };
}

template <typename MT, typename T, typename... Ts, typename... As, typename>
DeluxeAgent::DeluxeAgent(
    const AtomValue Kind, const id_t Id, const std::string &Name,
    MessagingSystem &S,
    std::function<std::tuple<Optional<Ts>...>(std::pair<MT, bool>)> &&MF,
    std::function<std::tuple<Optional<T>, Optional<Ts>...>(
        std::pair<As, bool>...)> &&F) noexcept
    : Agent(Kind, Id, Name, S, THISMEMBER(handleTrigger),
            DASLAVEHANDLERREF(AtomValue), DASLAVEHANDLERREF(int16_t),
            DASLAVEHANDLERREF(int32_t), DASLAVEHANDLERREF(int64_t),
            DASLAVEHANDLERREF(int8_t), DASLAVEHANDLERREF(long_double),
            DASLAVEHANDLERREF(std__string), DASLAVEHANDLERREF(uint16_t),
            DASLAVEHANDLERREF(uint32_t), DASLAVEHANDLERREF(uint64_t),
            DASLAVEHANDLERREF(uint8_t), DASLAVEHANDLERREF(unit_t),
            DASLAVEHANDLERREF(bool), DASLAVEHANDLERREF(double),
            DASLAVEHANDLERREF(float), DAMASTERHANDLERREF(AtomValue),
            DAMASTERHANDLERREF(int16_t), DAMASTERHANDLERREF(int32_t),
            DAMASTERHANDLERREF(int64_t), DAMASTERHANDLERREF(int8_t),
            DAMASTERHANDLERREF(long_double), DAMASTERHANDLERREF(std__string),
            DAMASTERHANDLERREF(uint16_t), DAMASTERHANDLERREF(uint32_t),
            DAMASTERHANDLERREF(uint64_t), DAMASTERHANDLERREF(uint8_t),
            DAMASTERHANDLERREF(unit_t), DAMASTERHANDLERREF(bool),
            DAMASTERHANDLERREF(double), DAMASTERHANDLERREF(float)),
      ExecutionPolicy(DeluxeExecutionPolicy::decimation(1)), OutputType(T::TT),
      NumberOfInputs(sizeof...(As)), MasterInputType(MT::TT),
      NumberOfMasterOutputs(NumberOfInputs), InputTypes({As::TT...}),
      InputNextPos(NumberOfInputs, 0), InputChanged(NumberOfInputs, false),
      InputValues(makeInputStorages<As...>()), MasterInputNextPos(0),
      MasterInputChanged(false),
      MasterInputValue(new typename TokenizedStorageForTypeList<
                       typename UnwrapDeluxeTuple<MT>::Type>::Type()),
      MasterOutputTypes({Ts::TT...}),
      FP(triggerHandlerFromProcessingFunctions(std::move(MF), std::move(F),
                                               seq_t<MT::Length>())),
      Slaves(NumberOfInputs) {
  ASSERT(Kind == atoms::AgentKind);
  LOG_TRACE_STREAM << "DeluxeAgent " << FullName << " is created." << std::endl;
  ASSERT(inv());
}

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

  // The assert must hold if \p this object was successfully constructed.
  STATIC_ASSERT((true && ... &&
                 (static_cast<size_t>(static_cast<token_size_t>(S0)) == S0)),
                "Unexpected error");
  // 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 << "DeluxeAgent " << FullName << "(" << Id
                   << ") sends to master ("
                   << static_cast<bool>(Master && *Master) << "): " << Value
                   << " (" << sizeof...(S0) << ")" << 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... Ts, size_t... S0>
void DeluxeAgent::sendToSlave(const size_t Pos, const DeluxeTuple<Ts...> &Value,
                              Seq<S0...>) noexcept {
  STATIC_ASSERT(sizeof...(Ts) == sizeof...(S0), "inconsistent arguments");
  ASSERT(inv() && Pos < NumberOfMasterOutputs &&
         MasterOutputTypes[Pos] == TypeToken<Ts...>::Value);

  // The assert must hold if \p this object was successfully constructed.
  STATIC_ASSERT((true && ... &&
                 (static_cast<size_t>(static_cast<token_size_t>(S0)) == S0)),
                "Unexpected error");
  // 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...}};

  // There is a handle and the referred *slave* is in a valid state.
  auto Slave = Slaves[Pos];

  LOG_TRACE_STREAM << "DeluxeAgent " << FullName << "(" << Id
                   << ") sends to slave (" << static_cast<bool>(Slave && *Slave)
                   << ") at position " << Pos << ": " << Value << " ("
                   << sizeof...(S0) << ")" << std::endl;

  if (Slave && *Slave) {
    // Handle each element of the tuple in a fold expression.
    (Slave->sendMessage(Message::create(atoms::Master::Value, Id, Indices[S0],
                                        std::get<S0>(Value))),
     ...);
  }
}

template <typename T>
void DeluxeAgent::saveInput(id_t Id, token_size_t Pos, T Value) noexcept {
  ASSERT(inv() && SlaveIds.find(Id) != SlaveIds.end() &&
         Pos == InputNextPos[SlaveIds.find(Id)->second] &&
         typeAtPositionOfToken(InputTypes[SlaveIds.find(Id)->second], Pos) ==
             TypeNumberOf<T>::Value);

  const size_t SlavePos = SlaveIds.at(Id);

  LOG_TRACE_STREAM << "DeluxeAgent " << FullName << "(" << Id
                   << ") saves value from slave at position " << SlavePos
                   << ": (" << static_cast<size_t>(Pos) << ") " << Value
                   << std::endl;

  // Save value.
  *static_cast<T *>(InputValues[SlavePos]->pointerTo(Pos)) = Value;

  // Update position of next value.
  if (++InputNextPos[SlavePos] == lengthOfToken(InputTypes[SlavePos])) {
    InputNextPos[SlavePos] = 0;
  }

  // Set flag.
  InputChanged[SlavePos] = true;

  ASSERT(inv());
}

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

  LOG_TRACE_STREAM << "DeluxeAgent " << 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;

  ASSERT(inv());
}

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

#undef DASLAVEHANDLEREF
#undef DAMASTERHANDLEREF
#undef DASLAVEHANDLEDEF
#undef DAMASTERHANDLEDEF
#undef DASLAVEHANDLEDEFN
#undef DAMASTERHANDLEDEFN
#undef DASLAVEHANDLENAME
#undef DAMASTERHANDLENAME

#endif // ROSA_DELUXE_DELUXEAGENT_HPP
