/***************************************************************************//**
 *
 * \file rosa/core/SystemBase.hpp
 *
 * \author David Juhasz (david.juhasz@tuwien.ac.at)
 *
 * \date 2017
 *
 * \brief Base implementation of the `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 `rosa::System` interface.
///
/// This implementation provides only *name* for `rosa::System`, identifiers for
/// `rosa::Unit` instances, and marking the `rosa::System` cleaned for
/// destruction.
///
/// \note Actual implementations of `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 `this` object.
  ///
  /// \pre `this`object is marked cleaned:\code
  /// isSystemCleaned()
  /// \endcode
  ~SystemBase(void);

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

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

  /// Indicates that `this` object has been cleaned and is ready for
  /// destruction.
  ///
  /// The field is initialized as 'false' and can be set by
  /// `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 `this` object
  ///
  /// \note The returned reference remains valid as long as `this` object is not
  /// destroyed.
  ///
  /// \return reference to `Name`
  const std::string &name(void) const noexcept override;

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

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

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

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

} // End namespace rosa

#endif // ROSA_LIB_CORE_SYSTEMBASE_HPP

