/* The Bakery Algorithm --- in PVM                  Author:  Tim Rolfe

      Clerk:
          This process accepts the customer requests in strick
          number order --- until it receives an EXIT message from
          the Controller.  Then the Clerk processes an order, it
          also waits a random length of time.  When no orders are
          pending, the Clerk waits a second and then checks for
          any pending messages.
*/
#include <iostream.h>
#include "Bakery.h"     // Pulls in a number of #includes, such as pvm3.h

#define DEBUG

void Clerk   ( int Ninit );  // Rank 2 process

void main ( int argc, char* argv[] )
{
   int Ninit;
   int MyTID, ParentTID;
   char ExitMsg[] = "Finished with Clerk process";

// Enroll in PVM
   MyTID = pvm_mytid();
   ParentTID = pvm_parent();

// Get the initial ticket number from the host
   pvm_recv( ParentTID, INIT );
   pvm_upkint ( &Ninit, 1, 1 );
// then process all requests until an EXIT request
   srand(time(NULL));     // Clerk uses rand()
   Clerk ( Ninit );

// Send message to screen on termination
   pvm_initsend (PvmDataRaw);
   pvm_pkstr ( ExitMsg );
   pvm_send  ( ParentTID, TEXT );
// Hand-shake --- advise host of exit
   pvm_initsend (PvmDataRaw);
   pvm_send  ( ParentTID, EXIT );

   pvm_exit();
}

/* Clerk process:  handle requests in strict order, starting from
                   the value passed as the parameter Ticket.
*/
void Clerk ( int Ticket )
{
   char  Line[128];
   int   bufID;         // Buffer ID to use with bufinfo
   int   Tag, Source, MsgLen;

   while (1)       // Will break out on an EXIT message from CONTROL
   {
      bufID = pvm_probe ( ANYTHING, ANYTHING );
 
      if ( bufID )
      {
         pvm_bufinfo ( bufID, &MsgLen, &Tag, &Source );
         if ( Tag == EXIT )
            break;
      }
//    NOTE:  NON-blocking receive --- combines MPI_Iprobe and MPI_Recv
      bufID = pvm_nrecv ( ANYTHING, Ticket );
      if ( bufID )      // The next request is available
      {//Randomized time to service this request
         int ServiceTime = int ( rand() * 10.0 / (RAND_MAX+1.0) );

         pvm_bufinfo ( bufID, &MsgLen, &Tag, &Source );
         pvm_upkstr  ( Line );

//       Just send exactly the same information back as the ACK
         pvm_initsend ( PvmDataRaw );
         pvm_pkstr( Line );
         pvm_send ( Source, Ticket );
         Ticket = Ticket % 999 + 1;    // Range is 1 to 999
         sleep(ServiceTime);           // Time to service request
      }
      sleep (1);// Wait a second, then check for a message
   }
// Consume the EXIT message and discard it.
   pvm_recv( Source, EXIT );
}
