#include <stdlib.h>
#include "../common.h"

#define NUMMCAST 1
#define MAXIMPL 5
#define NUMPES  CmiNumPes()

CpvDeclare(int, MtestHandle);
CpvDeclare(int, RecvmsgHandle);
CpvDeclare(int, AllDoneHandle);
CpvDeclare(int, impl);
CpvDeclare(int, maxsize);
CpvDeclare(double, StartTime);
CpvDeclare(comID, MyID);

void DistribIds(int ity)
{
  	Msg *m=(Msg *)CmiAlloc(sizeof(Msg));
  	comID id=ComlibInstance(ity, NUMPES);
	CpvAccess(MyID)=id;
  	m->id=id;
	CmiSetHandler(m, CpvAccess(MtestHandle));
  	CmiSyncBroadcastAllAndFree(sizeof(Msg), m);
}

void startnext()
{
  	Msg *m=(Msg *)CmiAlloc(sizeof(Msg));
  	m->id=CpvAccess(MyID);
	CmiSetHandler(m, CpvAccess(MtestHandle));
  	CmiSyncBroadcastAllAndFree(sizeof(Msg), m);
}
void all_done(Msg *m1)
{
  static int ad=0;
  static int junk=0;
  double totaltime;
  ad++;
  if (ad==NUMPES) {
  	junk++;
  	totaltime=CmiWallTimer()-CpvAccess(StartTime);
  	//CmiPrintf("%d Msgsize = %d Time = %f\n",CpvAccess(impl), (sizeof(Msg)+CpvAccess(maxsize)*sizeof(int)), totaltime/NUMMCAST); 
  	CmiPrintf("%f\t",totaltime/NUMMCAST); 
	CpvAccess(impl)++;
	if (junk >=MAXIMPL) {
		CmiPrintf("\n");
		CsdExitScheduler();
	}
     	else {
        	ad=0;
		startnext();
        }		
  }
}

void recv_msg(Msg *m)
{
  static int mc=0;
  static int counter=0;
  mc++; 
  comID id=m->id;

  //CmiPrintf("%d id.Impltype=%d\n",CmiMyPe(), id.ImplType);

  if (mc == NUMMCAST*(NUMPES)) {
  	Msg *m1=(Msg *)CmiAlloc(sizeof(Msg));
	CmiSetHandler(m1, CpvAccess(AllDoneHandle));
     	CmiSyncSendAndFree(0, sizeof(Msg), m1);
	mc=0;
	counter++;
     	if (CmiMyPe() && (counter >= MAXIMPL)) CsdExitScheduler();
  }
}

void Mtest(Msg *m)
{
  int i;
  if (CmiMyPe() >= NUMPES) {
  	CsdExitScheduler();
	return;
  }
  int *t=(int *)CmiAlloc(CmiNumPes()*sizeof(int));
  Msg *m1;

  //CmiPrintf("Mtest called in %d\n", CmiMyPe());
  for(i=0;i<(CmiNumPes());i++) t[i]=i;

  CpvAccess(StartTime)=CmiWallTimer();

  int msgsize=sizeof(Msg)+CpvAccess(maxsize)*sizeof(int);
  if (CmiMyPe()==0 && CpvAccess(impl)==0) CmiPrintf("%d\t",msgsize);
  for (i=0;i<NUMMCAST;i++) {
  	m1=(Msg *)CmiAlloc(msgsize);
  	m1->id=m->id;
  	CmiSetHandler(m1, CpvAccess(RecvmsgHandle));
  	EachToManyMulticast(m1->id, msgsize, m1, NUMPES, t);
  }
  CmiFree(t);
}


void Btest(int argc, char **argv)
{
  CpvInitialize(int, impl);
  CpvInitialize(int, maxsize);
  CpvInitialize(int, MtestHandle);
  CpvInitialize(int, RecvmsgHandle);
  CpvInitialize(int, AllDoneHandle);
  CpvInitialize(double, StartTime);
  CpvInitialize(comID, MyID);

  CpvAccess(impl)=atoi(argv[1]);
  CpvAccess(maxsize)=atoi(argv[2]);
  //CpvAccess(impl)=0;
  CpvAccess(MtestHandle)=CmiRegisterHandler((CmiHandler)Mtest);
  CpvAccess(RecvmsgHandle)=CmiRegisterHandler((CmiHandler)recv_msg);
  CpvAccess(AllDoneHandle)=CmiRegisterHandler((CmiHandler)all_done);
  CpvAccess(StartTime)=CmiWallTimer();

  ComlibInit();

  if (CmiMyPe()==0) {
  	DistribIds(CpvAccess(impl));
  }
}



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