//===-- deluxe/executionpolicies/AwaitBase.h --------------------*- C++ -*-===//
//
//                                 The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file deluxe/executionpolicies/AwaitBase.h
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Declaration of an *execution policy* that makes decisions depending
/// on input state of *slave* positions.
///
//===----------------------------------------------------------------------===//

#ifndef ROSA_LIB_DELUXE_EXECUTIONPOLICIES_AWAITBASE_H
#define ROSA_LIB_DELUXE_EXECUTIONPOLICIES_AWAITBASE_H

#include "rosa/deluxe/DeluxeExecutionPolicy.h"

#include <functional>

namespace rosa {
namespace deluxe {

/// Implementation of an *execution policy* that makes decisions depending on
/// whether new input has been received at some *slave* positions since the
/// laste triggering.
///
/// The class implements the \c rosa::deluxe::DeluxeExecutionPolicy interface
/// but delegates the defintion of the actual decision-making function to
/// subclasses.
///
/// \see rosa::deluxe::AwaitAll
/// \see rosa::deluxe::AwaitAny
class AwaitBase : public DeluxeExecutionPolicy {
protected:
  /// Set of *slave* positions to check.
  const std::set<size_t> Set;

  /// Type of decision-making function used in \c
  /// rosa::deluxe::AwaitBase::shouldProcess().
  using CheckerType = std::function<bool(std::set<size_t>::const_iterator,
                                         std::set<size_t>::const_iterator,
                                         std::function<bool(const size_t)>)>;

  // Decision-making function for \c rosa::deluxe::AwaitBase::shouldProcess().
  const CheckerType Checker;

  /// Protected constructor, only subclasses can instatiate the class.
  ///
  /// \param S set of *slave* positions to await input from
  /// \param Checker function that decides about execution
  AwaitBase(const std::set<size_t> &S, CheckerType &&Checker);

public:
  /// Tells if \p this object can handle the deluxe *unit* referred by \p H.
  ///
  /// Any *execution policy* based on this class can handle *agents* with at
  /// least as many *slave* positions as the largest one defined in \c
  /// rosa::deluxe::AwaitBase::Set.
  ///
  /// \param H reference to the *unit* to check
  /// \param S the system owning the *unit* referred by \p H
  ///
  /// \return if \p this object can handle the *unit* referred by \p H
  bool canHandle(const AgentHandle H, const DeluxeSystem &S) const
      noexcept override;

  /// Tells if processing function should be executed on the current triggering.
  ///
  /// Waiting for input allows execution when \c
  /// rosa::deluxe::AwaitBase::Checker evaluates to \c true with respect to \c
  /// rosa::deluxe::AwaitBase::Set and \p InputChanged.
  ///
  /// \param InputChanged flags indicating whether new input has been received
  /// at *slave* positions
  ///
  /// \return if to execute processing function
  bool shouldProcess(const std::vector<bool> &InputChanged) noexcept override;

private:
  /// Tells if \p this object can handle a *unit* with \p NumberOfInputs *slave*
  /// positions.
  ///
  /// \param NumberOfInputs the number of *slave* positions to consider
  ///
  /// \return if \p this object can handle a *unit* with \p NumberOfInputs
  /// *slave* positions
  bool canHandleNumberOfInputs(const size_t NumberOfInputs) const noexcept;

protected:
  /// Dumps the set of *slave* positions that \p this object checks.
  ///
  /// \return textual representation of \c rosa::deluxe::AwaitBase::Set of \p
  /// this object
  std::string dumpS(void) const noexcept;
};

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

#endif // ROSA_LIB_DELUXE_EXECUTIONPOLICIES_AWAITBASE_H
