#include <Messenger.hpp>
#include <PastisOStream.hpp>

#include <pastis_config.hpp>

#ifdef PASTIS_HAS_MPI
#include <mpi.h>
#endif // PASTIS_HAS_MPI

Messenger* Messenger::m_instance = nullptr;

void Messenger::create(int& argc, char* argv[])
{
  if (Messenger::m_instance == nullptr) {
    Messenger::m_instance = new Messenger(argc, argv);
  } else {
    std::cerr << "Messenger already created\n";
    std::exit(1);
  }
}

void Messenger::destroy()
{
  // One allows multiple destruction to handle unexpected code exit
  if (Messenger::m_instance != nullptr) {
    delete Messenger::m_instance;
    Messenger::m_instance = nullptr;
  }
}

Messenger::
Messenger(int& argc, char* argv[])
{
#ifdef PASTIS_HAS_MPI
  MPI_Init(&argc, &argv);
  MPI_Comm_rank(MPI_COMM_WORLD, &m_rank);
  MPI_Comm_size(MPI_COMM_WORLD, &m_size);

  if (m_rank != 0) {
    pout.setOutput(null_stream);
    perr.setOutput(null_stream);
  }
#endif // PASTIS_HAS_MPI
}

Messenger::
~Messenger()
{
#ifdef PASTIS_HAS_MPI
  MPI_Finalize();
#endif // PASTIS_HAS_MPI
}


void Messenger::barrier() const
{
#ifdef PASTIS_HAS_MPI
  MPI_Barrier(MPI_COMM_WORLD);
#endif // PASTIS_HAS_MPI
}

Array<int> Messenger::
_broadcast(Array<int>& array, int root_rank) const
{
  int size = array.size();
  MPI_Bcast(&size, 1,  MPI_INT, root_rank, MPI_COMM_WORLD);
  if (commRank() != root_rank) {
    array = Array<int>(size);
  }
  MPI_Bcast(&(array[0]), array.size(), MPI_INT, root_rank, MPI_COMM_WORLD);
  return array;
}