//===-- rosa/agent/SystemStateDetector.hpp ----------------------*- C++ -*-===//
//
//                                 The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/agent/SystemStateDetector.hpp
///
/// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Definition of *system state detector* *functionality*.
///
//===----------------------------------------------------------------------===//

#ifndef ROSA_AGENT_SYSTEMSTATEDETECTOR_HPP
#define ROSA_AGENT_SYSTEMSTATEDETECTOR_HPP

#include "rosa/agent/Functionality.h"
#include "rosa/agent/StateDetector.hpp"
#include "rosa/agent/SystemState.hpp"

#include "rosa/support/debug.hpp"

namespace rosa {
namespace agent {

/// System state conditions defining how the condition of a \c
/// rosa::agent::SystemState is saved in \c rosa::agent::SystemStateInformation.
enum class SystemStateCondition : uint8_t {
  STABLE = 0,         ///< The system state is stable
  DRIFTING = 1,       ///< The system state is drifting
  MALFUNCTIONING = 2, ///< The system state is malfunctioning
  UNKNOWN = 3         ///< The system state is unknown
};

/// TODO: write description
template <typename CONFDATATYPE> struct SystemStateInformation {
  // Make sure the actual type arguments are matching our expectations.
  STATIC_ASSERT((std::is_arithmetic<CONFDATATYPE>::value),
                "confidence type is not to arithmetic");

  /// The system state ID saved as an uint32_teger number
  uint32_t SystemStateID;
  /// The SystemStateConfidence shows the overall confidence value of the system
  /// state.
  CONFDATATYPE OverallDetectionConfidence;
  /// The SystemStateCondition shows the condition of a system state (stable,
  /// drifting, malfunctioning, or unknown)
  //@David: is it ok to name the variable exactly as the type is named?
  SystemStateCondition SystemStateCondition;
  /// The SystemStateIsValid saves the number of samples which have been
  /// inserted into the state after entering it.
  uint32_t NumberOfInsertedSamplesAfterEntrance;
  /// The SystemStateIsValid shows whether a state is valid or invalid.
  /// In this context, valid means that enough samples which are in close
  /// proximitry have been inserted into the state.
  bool SystemStateIsValid;
  /// The SystemStateJustGotValid shows whether a system state got valid
  /// (toggled from invalid to valid) during the current inserted sample.
  bool SystemStateJustGotValid;
  /// The SystemStateIsValidAfterReentrance shows whether a system state is
  /// valid after the variable changed back to it again.
  bool SystemStateIsValidAfterReentrance;
  /// The SystemIsStable shows whether a signa is stable and not
  /// drifting.
  bool SystemIsStable;
};

/// TODO: write description
template <typename INDATATYPE, typename CONFDATATYPE, typename PROCDATATYPE,
          HistoryPolicy HP, std::size_t NUMOFINPUTSIGNALS,
          std::size_t NUMOFOUTPUTSIGNALS>
class SystemStateDetector
    : public StateDetector<INDATATYPE, CONFDATATYPE, PROCDATATYPE, HP> {

  //@maxi added them to make it compilable is this what you wanted?
  using StateDetector =
      StateDetector<INDATATYPE, CONFDATATYPE, PROCDATATYPE, HP>;
  using PartFuncPointer = typename StateDetector::PartFuncPointer;

private:
  // For the convinience to write a shorter data type name
  using SystemStatePtr =
      std::shared_ptr<SystemState<INDATATYPE, CONFDATATYPE, PROCDATATYPE,
                                  NUMOFINPUTSIGNALS, NUMOFOUTPUTSIGNALS>>;

  /// The NextSystemStateID is a counter variable which stores the ID which
  /// the
  /// next system state shall have.
  uint32_t NextSystemStateID;

  /// The SystemStateHasChanged is a flag that show whether the observed
  /// system
  /// has changed its state.
  bool SystemStateHasChanged;

  /// The CurrentSystemState is a pointer to the (saved) system state in which
  /// the actual state of the observed system is.
  SystemStatePtr CurrentSystemState;

  /// The DetectedSystemStates is a history in that all detected system states
  /// are saved.
  DynamicLengthHistory<SystemStatePtr, HP> DetectedSystemStates;

  /// The FuzzyFunctionDelayTimeToGetBroken is the fuzzy function that gives
  /// the confidence whether the system is Broken because of an input change
  /// without an output change or vice versa. A small time gap between the two
  /// shall be allowed.
  PartFuncPointer FuzzyFunctionDelayTimeToGetBroken;

  /// The FuzzyFunctionDelayTimeToBeWorking is the fuzzy function that gives
  /// the
  /// confidence whether the system is still OK allthough an input change
  /// without an output change or vice versa.
  PartFuncPointer FuzzyFunctionDelayTimeToBeWorking;

public:
  /// TODO: write description
  SystemStateDetector(
      uint32_t MaximumNumberOfSystemStates,
      PartFuncPointer FuzzyFunctionDelayTimeToGetBroken,
      PartFuncPointer FuzzyFunctionDelayTimeToBeWorking) noexcept
      : NextSystemStateID(1), SystemStateHasChanged(false),
        CurrentSystemState(nullptr),
        DetectedSystemStates(MaximumNumberOfSystemStates),
        FuzzyFunctionDelayTimeToGetBroken(FuzzyFunctionDelayTimeToGetBroken),
        FuzzyFunctionDelayTimeToBeWorking(FuzzyFunctionDelayTimeToBeWorking) {}

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

  /// TODO: write description
  SystemStateInformation<CONFDATATYPE>
  detectSystemState(INDATATYPE Sample) noexcept {

    // dummy line
    Sample = 1;
  }
};

} // End namespace agent
} // End namespace rosa

#endif // ROSA_AGENT_SYSTEMSTATEDETECTOR_HPP
