#include "templates.h"
#include "templates.def.h"

int templates_redid;

void templates_init(void) 
{
  int i;
  for(i=0;i<CkNumPes();i++) {
    CProxy_templates_Collector<int>::ckNew(i);
  }
}

void templates_moduleinit(void)
{
  templates_redid = CProxy_templates_Reduction<int>::ckNew();
}

template <class dtype> void 
templates_Reduction<dtype>::submit(templates_Single<dtype> *msg)
{
  CProxy_templates_Reduction<dtype> red(thisgroup);
  red.remoteRecv(msg, 0);
}

template <class dtype> void
templates_Reduction<dtype>::Register(templates_ClientMsg *msg)
{
  cid = msg->cid;
  delete msg;
}

template <class dtype> void
templates_Reduction<dtype>::remoteRecv(templates_Single<dtype> *msg)
{
  data += msg->data;
  nreported++;
  if(nreported == CkNumPes()) {
    msg->data = data;
    CProxy_templates_Collector<dtype> col(cid);
    col.collect(msg);
    nreported = 0; data = 0;
  } else {
    delete msg;
  }
}

template <class dtype> 
templates_Collector<dtype>::templates_Collector(void)
{
  CProxy_templates_Reduction<dtype> red(templates_redid);
  if(CkMyPe()==0) {
    templates_ClientMsg *cmsg = new templates_ClientMsg(thishandle);
    red.Register(cmsg, 0);
  }
  templates_Single<dtype> *m = new templates_Single<dtype>((dtype)(CkMyPe()+1));
  red.submit(m, CkMyPe());
}

template <class dtype> void
templates_Collector<dtype>::collect(templates_Single<dtype> *msg)
{
  dtype data = msg->data;
  delete msg;
  if(data != (dtype) ((CkNumPes()*(CkNumPes()+1))/2)) {
    CkError("templates: test failed!\n");
  }
  finishTest();
}
