/*
Simple Array Reduction test program--
Orion Sky Lawlor, olawlor@acm.org, 11/15/1999

This program shows how to use the Array mangager's 
reduction routines.
 */
#include <stdio.h>
#include <string.h>
#include "hello.decl.h"

CkChareID mid;
CProxy_Hello arr;
int nElements;

class HiMsg : public CMessage_HiMsg
{
  int data;
};
typedef struct {
	int reductionsRemaining;
} myReductionCounter;

//Set this to 1 to test the set-wise reductions;
// otherwise the reduction will be a sum.
#define REDUCE_SET 1

void printIntReductionHandler(void *param,int dataSize,void *data)
{
	CkPrintf("**********************************************\n");
	CkPrintf("*** Final reduction handler called-- %d bytes:\n",dataSize);
#if REDUCE_SET
//Is a reduction set--parse each element
	CkReduction::setElement *cur=(CkReduction::setElement *)data;
	while (cur!=NULL)
	{
		CkPrintf("*** %d bytes: '%s'\n",cur->dataSize,(char *)cur->data);
		cur=cur->next();
	}
#else
//Not a reduction set-- just some sort of data
		CkPrintf("*** as int[0]: %d\n",((int *)data)[0]);
		CkPrintf("*** as int[1]: %d\n",((int *)data)[1]);
#endif
		
	CkPrintf("**********************************************\n");
	myReductionCounter *c=(myReductionCounter *)param;
	c->reductionsRemaining--;
	if (c->reductionsRemaining<=0)
	{//We're finished-- tell main to quit
		CProxy_main mproxy(mid);
		mproxy.maindone();
	} else 
	{//Broadcast a "Hi" again
		 //for (int i=0;i<nElements;i++) arr[i].SayHi(new HiMsg);
		 arr.SayHi(new HiMsg);
	}
}

class main : public Chare
{
public:
  main(CkMigrateMessage *m) {}
  main(CkArgMsg* m)
  {
    if(m->argc < 2) {
      CkAbort("Usage: hello <nElements>\n");
    }
    nElements = atoi(m->argv[1]);
    delete m;
    CkPrintf("Running Hello on %d processors for %d elements\n",
	     CkNumPes(),nElements);
    mid = thishandle;

    arr = CProxy_Hello::ckNew(nElements);

    myReductionCounter *c=new myReductionCounter;
    c->reductionsRemaining=2;

    arr.setReductionClient(printIntReductionHandler,(void *)c);
    
    arr.SayHi(new HiMsg);//Broadcast a Hi
  };

  void maindone(void)
  {
    CkPrintf("All done\n");
    CkExit();
  };
};

class Hello : public ArrayElement1D
{
	 int nTimes;
public:
  Hello() {nTimes=0;}

  Hello(CkMigrateMessage *m) {}

  void SayHi(HiMsg *m)
  {
  	int f[2];
	f[0]=thisIndex*(thisIndex+1)+2;
	f[1]=thisIndex*(thisIndex+4)-2;
	CkPrintf("Contributing to reduction %d, element %04d\n",nTimes++,thisIndex);
#if REDUCE_SET
	//Reducing to a set-- contribute some random string
	char buf[100];
	sprintf(buf,"I'm %d, running on PE %d.  f=%d.",thisIndex,CkMyPe(),f[0]);
	contribute(strlen(buf)+1,(void *)buf,CkReduction::set);
#else
	//Not reducing to a set-- just contribute an pair of integers
  	contribute(2*sizeof(int),(void *)f,CkReduction::sum_int);
#endif
  }
};

#include "hello.def.h"

