#include <utils/Messenger.hpp>
#include <utils/RandomEngine.hpp>

std::unique_ptr<RandomEngine> RandomEngine::m_instance;

bool
isSynchronized(const RandomEngine& random_engine)
{
  const uint64_t current_seed      = random_engine.getCurrentSeed();
  const uint64_t parallel_max_seed = parallel::allReduceMax(current_seed);

  return parallel::allReduceAnd(current_seed == parallel_max_seed);
}

uint64_t
RandomEngine::getCurrentSeed() const
{
  std::ostringstream ostr;
  ostr << m_random_engine;

  std::istringstream istr(ostr.str());

  uint64_t current_seed;
  istr >> current_seed;

  return current_seed;
}

void
RandomEngine::create()
{
  m_instance = std::unique_ptr<RandomEngine>(new RandomEngine);
}

void
RandomEngine::destroy()
{
  m_instance.reset();
}

RandomEngine::RandomEngine()
{
  this->resetRandomSeed();
}

void
RandomEngine::setRandomSeed(const uint64_t random_seed)
{
  m_random_engine = std::default_random_engine(random_seed);

  std::cout << " * setting " << rang::fgB::green << "random seed" << rang::style::reset << " to " << rang::fgB::yellow
            << random_seed << rang::style::reset << '\n';
}

void
RandomEngine::resetRandomSeed()
{
  uint64_t random_seed = std::random_device{}();
  parallel::broadcast(random_seed, 0);

  this->setRandomSeed(random_seed);
}