//===-- rosa/agent/RangeConfidence.hpp --------------------------*- C++ -*-===//
//
//                                 The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/agent/RangeConfidence.hpp
///
/// \author Benedikt Tutzer (benedikt.tutzer@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Definition of *RangeConfidence* *functionality*.
///
//===----------------------------------------------------------------------===//

#ifndef ROSA_AGENT_RANGECONFIDENCE_HPP
#define ROSA_AGENT_RANGECONFIDENCE_HPP

#include "rosa/agent/Functionality.h"
#include "rosa/agent/Abstraction.hpp"
#include "rosa/agent/FunctionAbstractions.hpp"

#include "rosa/support/debug.hpp"

#include <algorithm>
#include <vector>
#include <cmath>
#include <memory>

namespace rosa {
namespace agent {

/// Evaluates a vector of Abstractions at a given value and returns the results
/// as a vector
///
/// \note This implementation is supposed to be used to abstract ranges of
/// arithmetic types into vectors of another arithmetic type, which is
/// statically enforced.
///
/// \tparam T type to abstract from
/// \tparam A type to abstract a vector of to
template <typename T, typename A>
class RangeConfidence : public Abstraction<T, std::vector<A>>,
      private std::vector<PartialFunction<T, A>>{
  // Make sure the actual type arguments are matching our expectations.
  STATIC_ASSERT((std::is_arithmetic<T>::value), "abstracting not arithmetic");
  STATIC_ASSERT((std::is_arithmetic<A>::value),
      "abstracting not to arithmetic");

  // Bringing into scope inherited members.
  using std::vector<PartialFunction<T, A>>::size;
  using std::vector<PartialFunction<T, A>>::begin;
  using std::vector<PartialFunction<T, A>>::end;

public:
  /// Creates an instance by Initializing the underlying \c RangeAbstraction.
  ///
  /// \param Abstractions the Abstractions to be evaluated
  RangeConfidence(const std::vector<PartialFunction<T, A>> &Abstractions)
      : Abstraction<T, std::vector<A>>({}),
        std::vector<PartialFunction<T, A>>(Abstractions) {
  }

  /// Destroys \p this object.
  ~RangeConfidence(void) = default;

  /// Evaluates an Abstraction from type \p T to type \p A based on the set
  /// mapping.
  ///
  /// Results in the value associated by the set mapping to the argument, or
  /// \c rosa::agent::RangeAbstraction::Default if the actual argument is not
  /// included in any of the ranges in the set mapping.
  ///
  /// \param V value to abstract
  ///
  /// \return the abstracted value based on the set mapping
  std::vector<A> operator()(const T &V) const noexcept override {
    std::vector<A> ret;
    for (auto const& func : ((std::vector<PartialFunction<T, A>>)*this)){
      ret.push_back(func(V));
    }
    return ret;
  }
};
} // End namespace agent
} // End namespace rosa

#endif // ROSA_AGENT_RANGECONFIDENCE_HPP
