//===-- rosa/core/SystemBase.hpp -----------------------------*- C++ -*-===//
//
//                                 The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/core/SystemBase.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Base implementation of the \c rosa::System interface.
///
//===----------------------------------------------------------------------===//

#ifndef ROSA_CORE_SYSTEMBASE_HPP
#define ROSA_CORE_SYSTEMBASE_HPP

#include "rosa/core/System.hpp"

#include <atomic>

namespace rosa {

/// Base implementation of the \c rosa::System interface.
///
/// This implementation provides only equality checking and *name* for
/// \c rosa::System, identifiers for \c rosa::Unit instances, and marking the
/// \c rosa::System cleaned for destruction.
///
/// \note Actual implementations of \c rosa::System and derived interfaces are
/// supposed to inherit from this implementation.
class SystemBase : public System {
protected:
  /// Creates an instance.
  ///
  /// \note Protected constructor restrict instantiation for subclasses.
  ///
  /// \param Name name of the new instance
  SystemBase(const std::string &Name) noexcept;

public:
  /// Destroys \p this object.
  ///
  /// \pre \p this object is marked cleaned:\code
  /// isSystemCleaned()
  /// \endcode
  ~SystemBase(void);

  /// Tells whether \p this object is the same as \p Other.
  ///
  /// Two \c rosa::System instances are considered equal if they share a common
  /// \c rosa::SystemBase::Name member field. That should do among various
  /// subclasses.
  ///
  /// \param Other another \c rosa::System instance to compare to
  ///
  /// \return whether \p this object and \p Other is the same
  bool operator==(const System &Other) const noexcept override;

protected:
  /// The textual name of \p this object implementing \c rosa::System.
  const std::string Name;

private:
  /// Number of \c rosa::Unit instances constructed by \p this object.
  ///
  /// \note Should never be decremented!
  std::atomic<size_t> UnitCount;

  /// Indicates that \p this object has been cleaned and is ready for
  /// destruction.
  ///
  /// The field is initialized as \c false and can be set by
  /// \c rosa::SystemBase::markCleaned.
  ///
  /// \note Subclasses must set the flag upon destructing their instances, which
  /// indicates to the destructor of the base-class that all the managed
  /// resources has been properly released.
  std::atomic<bool> SystemIsCleaned;

public:
  /// Tells the name of \p this object
  ///
  /// \note The returned reference remains valid as long as \p this object is
  /// not destroyed.
  ///
  /// \return reference to \c rosa::SystemBase::Name
  const std::string &name(void) const noexcept override;

protected:
  /// Tells the next unique identifier to be used for a newly created
  /// \c rosa::Unit.
  ///
  /// The functions takes the current value of the internal counter
  /// \c rosa::SystemBase::UnitCount and then increments it.
  ///
  /// \note This is the only function modifying
  /// \c rosa::SystemBase::UnitCount.
  ///
  /// \return \c rosa::id_t which is unique within the context of \p this
  /// object.
  id_t nextId(void) noexcept override;

  /// Tells if \p this object has been marked cleaned and is ready for
  /// destruction.
  ///
  /// \return if \p this object is marked clean.
  bool isSystemCleaned(void) const noexcept override;

  /// Marks \p this object cleaned by setting
  /// \c rosa::SystemBase::SystemIsCleaned.
  ///
  /// \note Can be called only once when the System does not have any live
  /// \c rosa::Unit instances.
  ///
  /// \pre \p this object has not yet been marked as cleaned and it has no
  /// \c rosa::Unit instances registered:\code
  /// !isSystemCleaned() && empty()
  /// \endcode
  ///
  /// \post \p this object is marked cleaned:\code
  /// isSystemCleaned()
  /// \endcode
  void markCleaned(void) noexcept override;

  /// Tells the number of \c rosa::Unit instances constructed in the context of
  /// \p this object so far, including those being already destroyed.
  ///
  /// \return current value of \c rosa::SystemBase::UnitCount that is the number
  /// of \c rosa::Unit instances created so far
  size_t numberOfConstructedUnits(void) const noexcept override;
};

} // End namespace rosa

#endif // ROSA_CORE_SYSTEMBASE_HPP
