#include "pgm.h"

int migHandle;
static CkArray *arrayMgr;
CkChareID mainhandle;

UserArray::UserArray() : TempoArray()
{
  arrayMgr = thisArray;
}

UserArray::UserArray(CkMigrateMessage *msg) : TempoArray(msg)
{
  arrayMgr = thisArray;
  delete msg;
}

void
UserArray::pup(PUP::er &p)
{
  TempoArray::pup(p);
  if(p.isSizing())
  {
    sz = CthPackBufSize(thread_id);
    p(sz);
    p.advance(sz);
  }
  else if(p.isPacking())
  {
    p(sz);
    CthPackThread(thread_id, p.getBuf());
    p.advance(sz);
  }
  else if(p.isUnpacking())
  {
    p(sz);
    thread_id = CthUnpackThread(p.getBuf());
    p.advance(sz);
    CthAwaken(thread_id);
    tempoMessages = CmmNew();
    sleeping = 0;
  }
}

static void migrate_now(UserArray *element)
{
  CProxy_migrator pmg(migHandle);
  pmg.migrateElement(new MigrateInfo(element, (CkMyPe()+1)%2), CkMyPe());
  // CkPrintf("migrating from %d to %d\n", CkMyPe(), (CkMyPe()+1)%2);
  // CkPrintf("my tid is %p\n", CthSelf());
  CthSuspend();
  // CkPrintf("migrated to %d\n", CkMyPe());
}

void 
UserArray::startMigrate(void)
{
  int i, index;
  index = thisIndex;
  UserArray *element = (UserArray *) arrayMgr->getElement(CkArrayIndex1D(index));
  for(i=0;i<NITER;i++) {
    thread_id = CthSelf();
    sleeping = 1;
    migrate_now(element);
    element = (UserArray *) arrayMgr->getElement(CkArrayIndex1D(index));
  }
  CProxy_main pmain(mainhandle);
  pmain.Finish();
}

main::main(CkArgMsg *)
{
  CProxy_migrator::ckNew();
  CkArrayID aid = CProxy_UserArray::ckNew(1);
  CProxy_UserArray  pua(aid);
  pua[0].startMigrate();
  starttime = CkTimer();
  mainhandle = thishandle;
}

void 
main::Finish(void)
{
  endtime = CkTimer();
  CkPrintf("Time per migration = %lf seconds\n", (endtime-starttime)/NITER);
  CkExit();
}

#include "pgm.def.h"
