#include <cm/cmmd.h>
#include <cm/timers.h>
#include <math.h>

#include "fish.h"

#define RANDOM(r) 	((random()%10000)*r/10000.0) 
#define DT	0.1	/* time step resolution */
#define SIZE    256	/* width of ocean */
#define PROCS 	CMMD_partition_size()
#define	ME 	CMMD_self_address()

float cell[10][SIZE+2];  /* cell owned by each proc */
float count[10][SIZE+2]; /* neighbor counts */

/* the procs are laid from top to down in a 1-D array*/

main()
{
	struct arg_data args;
	int fish;
	int tsteps;
	int psteps;
	int x,y;
	int i,j,k,t;
	int next_proc;
	int ROW;

	CMMD_enable_host ();
	CMMD_receive_bc_from_host (&args, sizeof (struct arg_data));
    fish = args.fish;
    tsteps = args.tsteps;
    psteps = args.psteps;
    
    CMNA_timer_clear (0);
    CMNA_timer_start (0);

	ROW = SIZE/PROCS;

	/* initialize random number generator */
	srandom(CMMD_self_address());

	/* initialize cell */
	for (i=0;i<ROW+2;++i)
		for (j=0;j<SIZE+2;++j)
			cell[i][j]=0;

	/* place the fish in the cell */
	for (i=0;i<fish;++i) {
		x = RANDOM(ROW);
		y = RANDOM(SIZE);
		cell[x+1][y+1] = 1;
	}

	/* loop over all time steps */
	for (k=0,t=0;t<tsteps;++t) {
			
		/* exchange boundary row for odd/even procs */
		if (CMMD_self_address()%2) {
			next_proc = (ME + 1) % PROCS;
			CMMD_swap(next_proc,&cell[ROW+1][1],sizeof(float)*SIZE,
					    &cell[ROW][1],sizeof(float)*SIZE);
		  }
		else {
			next_proc = (ME - 1 + PROCS) % PROCS;
			CMMD_swap(next_proc,&cell[0][1],sizeof(float)*SIZE,
					    &cell[1][1],sizeof(float)*SIZE);
		 }	
		
		/* exchange boundary row for even/odd procs */
                if (CMMD_self_address()%2) {
                        next_proc = (ME - 1 + PROCS) % PROCS;
                        CMMD_swap(next_proc,&cell[0][1],sizeof(float)*SIZE,
                                            &cell[1][1],sizeof(float)*SIZE);
                  }
                else {
                        next_proc = (ME + 1) % PROCS;
                        CMMD_swap(next_proc,&cell[ROW+1][1],sizeof(float)*SIZE,
                                            &cell[ROW][1],sizeof(float)*SIZE);
                 }
		
		/* enforce boundary condition */
		if (ME == 0)
			for (i=0;i<SIZE+2;++i)
				cell[0][i] = 0;
		if (ME+1 == PROCS)
			for (i=0;i<SIZE+2;++i)
				cell[ROW+1][i] = 0;

		/* compute number of neighbors */
		for (i=1;i<=ROW;++i)
			for (j=1;j<=SIZE;++j) 
				count[i][j] = cell[i-1][j-1] + cell[i-1][j]
					+ cell[i-1][j+1] + cell[i][j-1] 
					+ cell[i][j+1] + cell[i+1][j-1]
					+ cell[i+1][j] + cell[i+1][j+1];

		/* determine life or death */
		for (i=1;i<=ROW;++i)
			for (j=1;j<=SIZE;++j)
				if ((cell[i][j]==0)&&(count[i][j]==3))
					cell[i][j] = 1;
				else if (count[i][j]<=1)
					cell[i][j] = 0;
				else if (count[i][j]>=4)
					cell[i][j] = 0;

		/* send info. to host for display */
		if (++k > psteps) {
			k = 0;
			CMMD_send(CMMD_host_node(),0,&cell[1][0],
					sizeof(float)*ROW*(SIZE+2));
		}
		
	}

	/* synchronize with host to end program */
    CMNA_timer_stop (0);
    CMMD_reduce_to_host_double (CMNA_timer_busy (0), CMMD_combiner_dmax);

	return;
}