//===-- examples/basic-system/basic-system.cpp ------------------*- C++ -*-===//
//
//                                 The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file examples/basic-system/basic-system.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief A simple example on the basic \c rosa::System and \c rosa::Unit
/// classes.
///
//===----------------------------------------------------------------------===//

#include "rosa/config/version.h"

#include "rosa/core/System.hpp"
#include "rosa/core/Unit.h"

#include "rosa/support/log.h"
#include "rosa/support/terminal_colors.h"

using namespace rosa;
using namespace rosa::terminal;

/// A dummy wrapper for testing \c rosa::System.
///
/// \note Since we test \c rosa::System directly here, we need to get access to
/// its protected members. That we do by imitating to be a decent subclass of
/// \c rosa::System, while calling protected member functions on an object of a
/// type from which we actually don't inherit.
struct SystemTester : protected System {
  static constexpr AtomValue UnitKind = atom("unit");

  static Unit &createMyUnit(System *S,
                            const std::string &Name = std::string()) {
    return ((SystemTester *)S)
        ->createUnit<Unit, System>([&Name](const rosa::id_t Id,
                                           System &S) noexcept {
          const std::string N(
              Name.empty()
                  ? "Unit_" + std::to_string(S.numberOfConstructedUnits())
                  : Name);
          return new Unit(UnitKind, Id, N, S);
        });
  }

  static void destroyMyUnit(System *S, Unit &U) {
    ((SystemTester *)S)->destroyUnit(U);
  }
};

int main(void) {
  LOG_INFO_STREAM << library_string() << " -- " << Color::Red
                  << "basic-system example" << Color::Default << '\n';

  std::unique_ptr<System> S = System::createSystem("Sys");
  System *SP = S.get();
  Unit &Unit1 = SystemTester::createMyUnit(SP),
       &Unit2 = SystemTester::createMyUnit(SP, "Second"),
       &Unit3 = SystemTester::createMyUnit(SP);
  SystemTester::destroyMyUnit(SP, Unit1);
  SystemTester::destroyMyUnit(SP, Unit3);
  LOG_INFO_STREAM << "Dumping Unit2\n" << Unit2 << '\n';
  SystemTester::destroyMyUnit(SP, Unit2);
  return 0;
}
