/*******************************************************************************
 *
 * File:     System.cpp
 *
 * Contents: Implementation of System base-class.
 *
 * Copyright 2017
 *
 * Author: David Juhasz (david.juhasz@tuwien.ac.at)
 *
 ******************************************************************************/

#include "rosa/core/System.h"
#include "rosa/core/Unit.h"
#include "rosa/config/config.h"
#include "rosa/support/debug.hpp"
#include "rosa/support/log.h"

namespace rosa {

System::System(const std::string &Name) noexcept : Name(Name),
                                                   CountUnits(0) {
  LOG_TRACE("Creating System (" + Name + ")");
}

System::~System(void) {
  LOG_TRACE("Destroying System (" + Name + ")");
  if (!empty()) {
    ROSA_CRITICAL("Trying to destroy a non-empty System");
  }
}

Unit &System::createUnit(UnitCreator C, const std::string &Name) noexcept {
  const uint64_t Id = ++CountUnits;
  const std::string N = Name.empty() ? "Unit_" + std::to_string(Id) : Name;
  Unit *U = C(Id, N, *this);
  // Scope protected container access.
  {
    // Obtain exclusive access and instert the Unit.
    std::lock_guard<std::mutex> L(RegisterMutex);
    auto result = Units.insert(U);
    if (!result.second) {
      ROSA_CRITICAL("Could not register Unit");
    }
  }
  LOG_TRACE("Unit created and registered (" + U->FullName + ")");
  return *U;
}

void System::destroyUnit(Unit &U) noexcept {
  ASSERT(Units.find(&U) != Units.end());
  LOG_TRACE("Destroying Unit (" + U.FullName + ")");
  // Scope protected container access.
  {
    // Obtain exclusive access and remove the Unit.
    std::lock_guard<std::mutex> L(RegisterMutex);
    auto result = Units.erase(&U);
    // NOTE: This case is catched by assertion when that is enabled.
    if (!result) {
      ROSA_CRITICAL("Trying to remove unregistered Unit");
    }
  }
  delete &U;
}

size_t System::numberOfConstructedUnits(void) const noexcept {
  return CountUnits;
}

size_t System::numberOfLiveUnits(void) const noexcept { return Units.size(); }

bool System::empty(void) const noexcept { return numberOfLiveUnits() == 0; }

} // End namespace rosa

