#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
#include <math.h>
#include <mpi.h>

#define width 200
#define height 200
#define iter 500
#define iteration (10000000L)
#define xmin -2.0
#define xmax 2.0
#define ymin -2.0
#define ymax 2.0

#define max(x,y) (x > y ? x : y)
#define min(x,y) (x < y ? x : y)

int checkPoint(double complex c, int *n, double complex *seq)
{

	int k;
	double complex z = 0;
	double complex new;
	*n = 0;
	for(k = 0;k < iter;k++)
	{
		z = z*z + c;
		seq[k] = z;
		if(creal(z)*creal(z) + cimag(z) *cimag(z) > 10)
		{
			*n = k;
			return 1;
		}
	}
	return 0;
}
int main(int argc, char ** argv)
{
	FILE* fl;
	int i,j,n,ix,iy,t;
	double complex c;
	int *image = NULL;
	double complex *seq = NULL;
	int *buff = NULL;
	int max,min,range;
	
	int mpistate,size,rank;
	MPI_Status mpistatus;

	MPI_Init(&argc,&argv);
	MPI_Comm_size(MPI_COMM_WORLD,&size);
	MPI_Comm_rank(MPI_COMM_WORLD,&rank);

	
	if((image = (unsigned int*)malloc(width*height*sizeof(unsigned int))) == NULL)
	{
		fprintf(stderr,"Failed to malloc memory for the image\n");
	}
	if((seq = (double complex*)malloc(iter*sizeof(unsigned int))) == NULL)
	{
		fprintf(stderr,"Failed to malloc memory for the sequence\n");
	}

	for(i = 0; i < width*height;i++)
	{
		image[i] = 0;
	}
	for(t = 0;t < iteration;t++)
	{
		c = 6*drand48() - 3 + (6*drand48()-3)*I;
		if(checkPoint(c,&n,seq))
		{
			for(i = 0; i < n;i++)
			{
				ix = .3 * width * (creal(seq[i]) + .5) + width/2;
				iy = .3 * height * cimag(seq[i]) + height/2;
				if(ix >=0 && iy >= 0 && ix < width && iy < height)
					image[iy*width+ix]++;
			}
		}
	}
	MPI_Barrier(MPI_COMM_WORLD);
	if(rank == 0)
	{
		printf("Passed the MPI_Barrier\n");
		if((buff = (unsigned int *)malloc(width*height*sizeof(unsigned int)))==NULL)
			fprintf(stderr,"Failed to allocate memory for the buffer\n");
		
		for(i = 1;i<size;i++)
		{
			if((mpistate=MPI_Recv(buff,width*height,MPI_INT,i,MPI_ANY_TAG,MPI_COMM_WORLD,&mpistatus)) != MPI_SUCCESS)
				fprintf(stderr,"MPI-Receive failed for rank %d\n",i);
			else
				fprintf(stderr,"MPI-Receive success from rank%d\n",mpistatus.MPI_SOURCE);
			for(j = 0;j < width*height;j++)
			{
				image[j]+=buff[j];
			}
		}

		if((fl=fopen("image_buddha_mpi.pgm","w"))==NULL)
		{
			fprintf(stderr,"Failed to open the image file");
		}
		fprintf(fl,"P5\n#Copyright (C) 2007 Bryan Ward\n%d\t%d\n255\n",width,height);
	
		max = image[0];
		min = image[0];
		for(i = 0; i < width*height;i++)
		{
			max = max(max,image[i]);
			min = min(min,image[i]);
		}
		printf("Max: %d\tMin: %d\n",max,min);
		range = max - min;
		for(i = 0; i < width*height;i++)
		{
			fprintf(fl,"%c",(unsigned char)(255*(image[i]-min)/range));
		}
		close(fl);
	}
	else
	{
		if((mpistate = MPI_Send(image,width*height,MPI_INT,0,rank,MPI_COMM_WORLD)) != MPI_SUCCESS)
			fprintf(stderr,"MPI-Send failed for rank %d\n",rank);
		else
			fprintf(stderr,"MPI-Send success for rank %d\n",rank);
	}
	free(seq);
	free(image);
	MPI_Finalize();
	return 0;
}
/*
Note:
This program doesn't quite work yet.  It is however code that I have been working on, and is almost operational.
*/