#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "charm++.h"
#include "jacobi90.h"
#include "jacobi.h"

int M; // readonly variable. All global variables must be readonly. 

#include "jacobi.def.h"

main::main(CkArgMsg *m)
{ 
  globalInit(&M);

  A = CProxy_jacobi::ckNew(M); // 1-D decomposition: array of 5 cells
  CkStartQD(EntryIndex(main,allDone,CkQdMsg), &thishandle);
  CkPrintf("main done\n");
};

void main::allDone(CkQdMsg *m)
{
  CkPrintf("Quiescence detected. stopping\n");
  CkExit();
};

jacobi::jacobi(ArrayElementCreateMessage *msg) : ArrayElement(msg) 
{ 
 static procInit = 0;
 if (procInit == 0)
 {
    procInit = 1;
    processorInit();
 }

 CkPrintf("[%d]: Element %d created\n", CkMyPe(), thisIndex); 
 int i = 10;
 int j= 100;
 chunkInit(&i, &j, (char **)&data); // each cell 10x100

/*
 for (i=0; i<4; i++)
    for (j=0; j<4; j++)
      CkPrintf("%f ", data->temperature[i][j]);
*/

 count = 2;
 iterations = 0;
 sendToNeighbors();

 finishConstruction(); 
};

void jacobi::borderValues(DataMsg *m)
{
 CkPrintf("[%d] A[%d]: received message from nbr\n", CkMyPe(), thisIndex);

 copyBorder(data, m->b, &m->fromLeft);

 if ((0 == --count)  && (++iterations < 3))
   {
     nextIteration(data);

     count = 2;
     sendToNeighbors();
   }
};

void jacobi::sendToNeighbors()
{
  CkPrintf("[%d] A[%d]: sending to %d and %d\n", CkMyPe(), thisIndex,
	   (thisIndex+1)%M, (M+thisIndex-1)%M );
 CProxy_jacobi B(thisAID);

 DataMsg * d = new DataMsg;
 d->fromLeft = 0;
 fillBorder(data, d->b, &d->fromLeft);
 B[(M+thisIndex-1)%M].borderValues(d);

 CkPrintf("[%d] A[%d]: sending to %d \n", CkMyPe(), thisIndex, (thisIndex+1)%M);
 d = new DataMsg;
 d->fromLeft = 1;
 fillBorder(data, d->b, &d->fromLeft);
 B[(thisIndex+1)%M].borderValues(d);

};

jacobi::jacobi(ArrayElementMigrateMessage *m):
  ArrayElement(m)
{
  finishMigration();

};

// for migration, need to write pack interface.

extern "C" void myprint_(int *i)
{
  CkPrintf("printout: %p. \n",i);
}

