//===-- rosa/deluxe/DeluxeAgent.hpp -----------------------------*- C++ -*-===//
//
//                                 The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \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 <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 DAHANDLERNAME(N) handleSlave_##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 DAHANDLERDEFN(T, N)                                                    \
  void DAHANDLERNAME(N)(atoms::Slave, id_t SlaveId, T Value) noexcept {        \
    saveInput(SlaveId, Value);                                                 \
  }

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

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

///@}

namespace rosa {
namespace deluxe {

/// Specialization of \c rosa::Agent for *agent* role of the *deluxe interface*.
///
/// \see \c rosa::deluxe::DeluxeContext
///
/// \invariant All input-related container objects have a size matching
/// \c rosa::deluxe::DeluxeAgent::NumberOfInputs, thus having a corresponding
/// entry for each input. Types of input values are consistent throughout all
/// the input-related containers. 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;

public:
  /// Template alias for function objects used to process input and generate
  /// output for \c rosa::deluxe::DeluxeAgent.
  ///
  /// The output generated by the function is optional as an agent may decide
  /// not to output anything at some situation.
  ///
  /// \note The function used for \c D is to be \c noexcept.
  ///
  /// \tparam T type of output
  /// \tparam As types of input values
  template <typename T, typename... As>
  using D = std::function<Optional<T>(std::pair<As, bool>...)>;

  /// The type of values produced by \p this object.
  ///
  /// That is the type of values \p this object sends to its *master*.
  ///
  /// \see \c rosa::deluxe::DeluxeAgent::master
  const TypeNumber OutputType;

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

private:

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

  /// 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::D.
  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::deluxe::DeluxeAgent::InputTypes.
  ///
  /// \note The position of a value in the \c rosa::AbstractTokenizedStorage
  /// indicates which argument of \p this object's processing function it is.
  /// See also \c rosa::deluxe::DeluxeAgent::D.
  const std::unique_ptr<AbstractTokenizedStorage> InputValues;

  /// 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 function processing *slave* inputs and generating optional
  /// output to *master* is captured in a lambda expression that is in turn
  /// wrapped in a \c std::function object. The lambda expression calls the
  /// processing function with the actual input data and sends its result -- if
  /// any -- to *master* by calling \c rosa::deluxe::DeluxeAgent::sendToMaster.
  /// Also, all the flags stored in \c rose::deluxe::DeluxeAgent::InputChanged
  /// are reset when the current input values are processed. The function
  /// \c rosa::deluxe::DeluxeAgent::handleTrigger needs only to call the
  /// function object.
  ///
  /// \see \c rosa::deluxe::DeluxeAgent::triggerHandlerFromProcessingFunction
  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::D.
  ///
  /// \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 whether types \p As... match the input types of \p this object.
  ///
  /// \tparam As types to match against values in
  /// \c rosa::deluxe::DeluxeAgent::InputTypes
  ///
  /// \return if types \p As... match \c rosa::TypeNumber values stored in
  /// \c rosa::deluxe::DeluxeAgent::InputTypes
  template <typename... As> bool inputTypesMatch(void) 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 The type arguments \p As... match the input types of \p this object
  /// and the provided indices \p S0... constitute a proper sequence for
  /// accessing input values and their change flags: \code
  /// inputTypesMatch<As...>() && sizeof...(As) == sizeof...(S0)
  /// \endcode
  template <typename... As, size_t... S0>
  std::tuple<std::pair<As, bool>...> prepareCurrentInputs(Seq<S0...>) const
      noexcept;

  /// Invokes a processing function matching the output and input 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 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... As, size_t... S0>
  static Optional<T> invokeWithTuple(D<T, As...> F,
                                     std::tuple<std::pair<As, bool>...> Args,
                                     Seq<S0...>) noexcept;

  /// Wraps a processing function 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 T type of output
  /// \tparam As types of input values
  ///
  /// \param F function processing inputs and generating output
  ///
  /// \pre Template arguments \p T and \p As... match the corresponding
  /// types \p this object was created with: \code
  /// OutputType == TypeNumberOf<T>::Value && inputTypesMatch<As...>()
  /// \endcode
  template <typename T, typename... As>
  H triggerHandlerFromProcessingFunction(D<T, As...> &&F) 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 F does not potentially throw exception.
  ///
  /// \tparam T type of output of \p F
  /// \tparam As types of input values of \p F
  ///
  /// \note Instantiation fails if any of the type arguments \p T and \p As...
  /// is not a built-in type.
  ///
  /// \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 F function to process input values and generate output with
  ///
  /// \pre Statically, all of the type arguments \p T and \p As... is a
  /// built-in type: \code
  /// TypeListSubsetOf<TypeList<T, As...>, BuiltinTypes>::Value
  /// \endcode Dynamically, the instance is created as of kind
  /// \c rosa::deluxe::atoms::AgentKind: \code
  /// Kind == rosa::deluxe::atoms::AgentKind
  /// \endcode
  template <typename T, typename... As,
            typename = std::enable_if_t<
                TypeListSubsetOf<TypeList<T, As...>, BuiltinTypes>::Value>>
  DeluxeAgent(const AtomValue Kind, const id_t Id, const std::string &Name,
              MessagingSystem &S, D<T, As...> &&F) noexcept;

  /// Destroys \p this object.
  ~DeluxeAgent(void) 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*.
  ///
  /// \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 type of values consumed from the *slave* at a position.
  ///
  /// That is the type of values \p this object expect to be sent to it by its
  /// *slave* registered at position \p Pos.
  ///
  /// \see \c rosa::deluxe::DeluxeAgent::slave
  ///
  /// \param Pos position of *slave*
  ///
  /// \return \c rosa::TypeNumber representing the type of values consumed from
  /// the *slave* at position \p Pos
  ///
  /// \pre \p Pos is a valid index of input: \code
  /// Pos < NumberOfInputs
  /// \endcode
  TypeNumber inputType(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.
  ///
  /// \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:
  /// \code
  /// Pos < NumberOfInputs &&
  /// (!Slave ||
  /// (unwrapAgent(*Slave.)Kind == rosa::deluxe::atoms::SensorKind &&
  ///  static_cast<const DeluxeSensor &>(unwrapAgent(*Slave)).OutputType ==
  ///  InputTypes[Pos]) ||
  /// (unwrapAgent(*Slave).Kind == rosa::deluxe::atoms::AgentKind &&
  ///  static_cast<const DeluxeAgent &>(unwrapAgent(*Slave)).OutputType ==
  ///  InputTypes[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.
  ///
  /// \tparam T type of the value to send
  ///
  /// \param Value value to send
  ///
  /// \pre \p T matches \c rosa::deluxe::DeluxeiAgent::OutputType: \code
  /// OutputType == TypeNumberOf<T>::Value
  /// \endcode
  template <typename T> void sendToMaster(const T &Value) 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.
  void handleTrigger(atoms::Trigger) noexcept;

  /// Stores a new input value from a *slave*.
  ///
  /// The function stores \p Value 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.
  ///
  /// \note Utilized by member functions of group \c DeluxeAgentInputHandlers.
  ///
  /// \tparam T type of input to store
  ///
  /// \param Id unique identifier of *slave*
  /// \param Value the input value to store
  ///
  /// \pre The *slave* with \p Id is registered and the input from it is
  /// expected to be of type \p T: \code
  /// SlaveIds.find(Id) != SlaveIds.end() &&
  /// InputTypes[SlaveIds.find(Id)->second] == TypeNumberOf<T>::Value
  /// \endcode
  template <typename T> void saveInput(id_t Id, 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. 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 DAHANDLERDEF.
  ///
  /// \note Keep these definitions in sync with \c rosa::BuiltinTypes.
  ///
  ///@{

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

  /// @}

};

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

/// Template \c struct whose specializations provide a recursive implementation
/// for \c rosa::deluxe::DeluxeAgent::inputTypesMatch.
///
/// \note Matching a list of types \p As... against a \c std::vector of
/// \c rosa::TypeNumber values, \c InputTypes, like \code
/// bool match = InputTypesMatchImpl<As...>::f(InputTypes, 0);
/// \endcode
///
/// \tparam As types to match
template <typename... As> struct InputTypesMatchImpl;

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

/// Template specialization for the terminal case, when no type remains to
/// check.
template <> struct InputTypesMatchImpl<> {
  /// Tells whether \p Pos is the number of values stored in \p InputTypes.
  ///
  /// In this terminal case, there is no more types to matchi 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 InputTypes. That is true if \p Pos points exactly to the end of
  /// \p InputTypes.
  ///
  /// \param InputTypes container of \c rosa::TypeNumber values to match
  /// types against
  /// \param Pos position in \p InputTypes to start matching at
  ///
  /// \return if \p Pos is the number of values stored in \p InputTypes
  static bool f(const std::vector<TypeNumber> &InputTypes,
                size_t Pos) noexcept {
    return Pos == InputTypes.size();
  }
};

} // End namespace

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

template <typename... As, size_t... S0>
std::tuple<std::pair<As, bool>...>
    DeluxeAgent::prepareCurrentInputs(Seq<S0...>) const noexcept {
  // Need to indirectly reference \c rosa::deluxe::DeluxeAgent::inputTypesMatch
  // inside \c ASSERT because of the comma in its template argument list.
  auto MFP = &DeluxeAgent::inputTypesMatch<As...>;
  ASSERT(inv() && (this->*MFP)() && sizeof...(As) == sizeof...(S0));

  return std::make_tuple(
      std::make_pair(*static_cast<const As *>(InputValues->pointerTo(S0)),
                     InputChanged[S0])...);
}

template <typename T, typename... As, size_t... S0>
Optional<T> DeluxeAgent::invokeWithTuple(
    D<T, As...> F,
    std::tuple<std::pair<As, bool>...> Args,
    Seq<S0...>) noexcept {
  ASSERT(sizeof...(As) == sizeof...(S0));
  return F(std::get<S0>(Args)...);
}

template <typename T, typename... As>
DeluxeAgent::H
DeluxeAgent::triggerHandlerFromProcessingFunction(D<T, As...> &&F) noexcept {
  // Need to indirectly reference \c rosa::deluxe::DeluxeAgent::inputTypesMatch
  // inside \c ASSERT because of the comma in its template argument list.
  auto MFP = &DeluxeAgent::inputTypesMatch<As...>;
  ASSERT(OutputType == TypeNumberOf<T>::Value && (this->*MFP)());

  return [ this, F ]() noexcept {
    using Indices = typename GenSeq<sizeof...(As)>::Type;
    auto Args = prepareCurrentInputs<As...>(Indices());
    std::fill(InputChanged.begin(), InputChanged.end(), false);
    Optional<T> R = invokeWithTuple(F, Args, Indices());
    if (R) {
      sendToMaster(*R);
    }
  };
}

template <typename T, typename... As, typename>
DeluxeAgent::DeluxeAgent(const AtomValue Kind, const id_t Id,
                         const std::string &Name, MessagingSystem &S,
                         D<T, As...> &&F) noexcept
    : Agent(Kind, Id, Name, S, THISMEMBER(handleTrigger),
            DAHANDLERREF(AtomValue), DAHANDLERREF(int16_t),
            DAHANDLERREF(int32_t), DAHANDLERREF(int64_t), DAHANDLERREF(int8_t),
            DAHANDLERREF(long_double), DAHANDLERREF(std__string),
            DAHANDLERREF(uint16_t), DAHANDLERREF(uint32_t),
            DAHANDLERREF(uint64_t), DAHANDLERREF(uint8_t), DAHANDLERREF(unit_t),
            DAHANDLERREF(bool), DAHANDLERREF(double), DAHANDLERREF(float)),
      OutputType(TypeNumberOf<T>::Value),
      NumberOfInputs(sizeof...(As)),
      InputTypes({TypeNumberOf<As>::Value...}),
      InputChanged(NumberOfInputs, false),
      InputValues(new TokenizedStorage<As...>()),
      FP(triggerHandlerFromProcessingFunction(std::move(F))),
      Slaves(NumberOfInputs) {
  ASSERT(Kind == atoms::AgentKind);
  LOG_TRACE("DeluxeAgent is created.");
  ASSERT(inv());
}

template <typename T>
void DeluxeAgent::sendToMaster(const T &Value) noexcept {
  ASSERT(inv() && OutputType == TypeNumberOf<T>::Value);

  // There is a handle and the referred *master* is in a valid state.
  if (Master && *Master) {
    Master->sendMessage(Message::create(atoms::Slave::Value, Id, Value));
  }
}

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

  size_t Pos = SlaveIds.at(Id);
  *static_cast<T *>(InputValues->pointerTo(Pos)) = Value;
  InputChanged[Pos] = true;

  ASSERT(inv());
}


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

#undef DAHANDLEREF
#undef DAHANDLEDEF
#undef DAHANDLEDEFN
#undef DAHANDLENAME

#endif // ROSA_DELUXE_DELUXEAGENT_HPP
