/* MPI_Process.h consolidates common code to MPI processes within a class.
 * Joel Adams, July 1997.
 * Updated:    January 2000.
 */

#include <iostream>                     // cin, cout, cerr, <<, >>, ...
using namespace std;

#include "mpi.h"                          // MPI_* functions

class MPI_Process
{
public:                                   // INTERFACE:
  MPI_Process(int & argc, char ** & argv); //  object constructor
  ~MPI_Process();                          //  destructor
  
  int rank() const;                       //  accessors
  int rank(const MPI_Comm & aCommunicator) const; 
  char * hostName() const;
  int numberOfProcesses() const;
  int numberOfProcesses(const MPI_Comm & aCommunicator) const;
  
  bool run();                             //  behavior (user-defined)

private:                                  // IMPLEMENTATION:
  int    numProcesses;                    //  processes in MPI_COMM_WORLD
  int    myRank;                          //  process # in MPI_COMM_WORLD
  char * myHost;                          //  name of local machine
  
  MPI_Process(const MPI_Process & original) //  disable copy constructor
  {}
};

const int MAX_HOST_NAME_LENGTH = 64;      // I hope this is big enough!

// Constructor for process initialization
inline MPI_Process::MPI_Process(int & argc, char ** & argv)
{
  MPI_Init(&argc, &argv);
  MPI_Comm_size(MPI_COMM_WORLD, &numProcesses);
  MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
  myHost = new char[MAX_HOST_NAME_LENGTH];
  int nameLength;
  MPI_Get_processor_name(myHost, &nameLength);
//  cout << myRank << " on " << myHost << " is initialized!" << endl;
}

// Destructor for process shutdown
inline MPI_Process::~MPI_Process()
{
  MPI_Finalize();
  delete [] myHost;
//  cout << myRank << " on " << myHost << " is terminating!" << endl;
}

// Accessor for process rank in MPI_COMM_WORLD
inline int MPI_Process::rank() const
{
  return myRank;
}

// Accessor for process rank in arbitrary communicator
inline int MPI_Process::rank(const MPI_Comm & aCommunicator) const
{
  int communicatorRank;
  MPI_Comm_rank(aCommunicator, &communicatorRank);
  return communicatorRank;
}

// Accessor for machine hosting process
inline char * MPI_Process::hostName() const
{
  return myHost;
}

// Accessor for number of processes in MPI_COMM_WORLD
inline int MPI_Process::numberOfProcesses() const
{
  return numProcesses;
}

// Accessor for number of processes in arbitrary communicator
inline int MPI_Process::numberOfProcesses(const MPI_Comm & aCommunicator) const
{
  int communicatorProcesses;
  MPI_Comm_size(aCommunicator, &communicatorProcesses);
  return communicatorProcesses;
}

// Copy constructor for temporaries, if desired
/*
inline MPI_Process::MPI_Process(const MPI_Process & original)
{
  numProcesses = original.NumberOfProcesses();   // copy # processes
  myRank = original.Rank();                      // copy rank
  myHost = new char [MAX_HOST_NAME_LENGTH];      // copy host name
  for (int i = 0; i < MAX_HOST_NAME_LENGTH; i++)
    myHost[i] = original.myHost[i];
}
*/

