#include <converse.h>
#include <string.h> /* for memcpy */

#define ITER_INI 0
#define ITER_MUL 237
#define ITER_ADD 701
#define NUM_MSGS 10000
#define NUM_DATA 1000

int handler_id;

void sendmsg(int count, int seed) {
  int data[NUM_DATA];
  int msg_size = CmiMsgHeaderSizeBytes + (NUM_DATA+1) * sizeof(int);
  void *msg_buf = CmiAlloc(msg_size);
  CmiSetHandler(msg_buf,handler_id);
  char *msg_data = (char *) msg_buf + CmiMsgHeaderSizeBytes;
  memcpy((void *)msg_data,(void *)&count, sizeof(int));
  msg_data += sizeof(int);
  data[0] = seed;
  for ( int i = 1; i < NUM_DATA; ++i ) {
    data[i] = data[i-1] * ITER_MUL + ITER_ADD;
  }
  memcpy((void *)msg_data,(void *)data, NUM_DATA*sizeof(int));
  int msg_dest = (CmiMyPe()+1) % CmiNumPes();
  CmiSyncSendAndFree(msg_dest,msg_size,msg_buf);
}

void checkmsg(void *msg_buf) {
  char *msg_data = (char *) msg_buf + CmiMsgHeaderSizeBytes;
  int count;
  memcpy((void *)&count,(void *)msg_data, sizeof(int));
  msg_data += sizeof(int);
  if ( count == NUM_MSGS ) {
    CmiPrintf("Last message received on Pe %d.\n",CmiMyPe());
    CsdExitScheduler();
    return;
  }
  int data[NUM_DATA];
  memcpy((void *)data,(void *)msg_data, NUM_DATA*sizeof(int));
  CmiFree(msg_buf);
  int seed = data[0];
  for ( int i = 1; i < NUM_DATA; ++i ) {
    seed = seed * ITER_MUL + ITER_ADD;
    if ( data[i] != seed ) {
      CmiPrintf("Diff on Pe %d msg %d at %d: %08x vs %08x\n",
	CmiMyPe(),count,i,data[i],seed);
    }
  }
  sendmsg(count+1,seed);
}

void startfn(int argc, char **argv) {
  handler_id = CmiRegisterHandler((CmiHandler)checkmsg);
  if ( ! CmiMyPe() ) {
    CmiPrintf("Testing %d procs for %d messages.\n",CmiNumPes(),NUM_MSGS);
  }
  CmiPrintf("Alive on processor %d.\n",CmiMyPe());
  sendmsg(0,ITER_INI);
}

int main(int argc, char **argv) {
  ConverseInit(argc,argv,startfn,0,0);
  return 0;
}

