/* Sequential Mandelbrot program */


#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <mpi.h>


#define		X_RESN	800       /* x resolution */
#define		Y_RESN	800       /* y resolution */

typedef struct rowtype 
{
  int rownum;
  int foo[X_RESN];
  int procnum;
} rowtype;

typedef struct complextype
	{
        float real, imag;
	} Compl;

int main(int argc,char *argv[])
{
    Window win;                            /* initialization for a window */
    unsigned int width, height,                  /* window size */
                 x, y,                           /* window position */
                 border_width,                   /*border width in pixels */
                 display_width, display_height,  /* size of screen */
                 screen;                         /* which screen */

    char *window_name = "Mandelbrot Set", *display_name = NULL;
    GC gc;
    unsigned long valuemask = 0;
    XGCValues values;
    Display *display;
    XSizeHints size_hints;
    Pixmap bitmap;
    XPoint points[800];
    FILE *fp, *fopen ();
    char str[100];
    XSetWindowAttributes attr[1];

    /* Mandlebrot variables */
    int i,j,k;
    Compl z,c;
    float lengthsq,temp;

    /* Our Non-MPI variables */
    rowtype rowstruct;
    int sendto;

    /* MPI variables */
    MPI_Status status;
    int myrank,msgtag,mysize;
    int data_tag=1,terminator_tag=0;    
   
    MPI_Init(&argc,&argv);
    MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
    MPI_Comm_size(MPI_COMM_WORLD,&mysize);

    if(myrank == 0) 
    {
        int count = 0;   /* counter for termination */
	int row = 0;     /* row being sent */
	int num;

	
        /* connect to Xserver */

	if (  (display = XOpenDisplay (display_name)) == NULL ) 
        {
	    fprintf (stderr, "drawon: cannot connect to X server %s\n",
				XDisplayName (display_name) );
	    exit (-1);
	}
	
	/* get screen size */
        
	screen = DefaultScreen (display);
	display_width = DisplayWidth (display, screen);
	display_height = DisplayHeight (display, screen);

	/* set window size */

	width = X_RESN;
	height = Y_RESN;

	/* set window position */

	x = 0;
	y = 0;

        /* create opaque window */

	border_width = 4;
	win = XCreateSimpleWindow (display, RootWindow (display, screen),
				x, y, width, height, border_width, 
				BlackPixel (display, screen), WhitePixel (display, screen));

	size_hints.flags = USPosition|USSize;
	size_hints.x = x;
	size_hints.y = y;
	size_hints.width = width;
	size_hints.height = height;
	size_hints.min_width = 300;
	size_hints.min_height = 300;
	
	XSetNormalHints (display, win, &size_hints);
	XStoreName(display, win, window_name);

        /* create graphics context */

	gc = XCreateGC (display, win, valuemask, &values);

	XSetBackground (display, gc, WhitePixel (display, screen));
	XSetForeground (display, gc, BlackPixel (display, screen));
	XSetLineAttributes (display, gc, 1, LineSolid, CapRound, JoinRound);

	attr[0].backing_store = Always;
	attr[0].backing_planes = 1;
	attr[0].backing_pixel = BlackPixel(display, screen);

	XChangeWindowAttributes(display, win, CWBackingStore | CWBackingPlanes | CWBackingPixel, attr);

	XMapWindow (display, win);
	XSync(display, 0);

        //printf("before for loop mysize is %d\n",mysize);
	for (num=1; num < mysize; num++) 
        {
	    MPI_Send(&row,1,MPI_INT,num,data_tag,MPI_COMM_WORLD);
	    count++;
	    row++;
	}
        //printf("after for loop in master\n");
	
	do 
        {
	  //printf("before receive in master do-while\n");	  
	    MPI_Recv(&rowstruct,X_RESN+2,MPI_INT,MPI_ANY_SOURCE,MPI_ANY_TAG,MPI_COMM_WORLD,&status);
	    //printf("after receive in master do-while\n");	  
	    count--;
	    if (row < Y_RESN) 
            {
	        MPI_Send(&row,1,MPI_INT,rowstruct.procnum,data_tag,MPI_COMM_WORLD);
	        row++;
	        count++;
	    }
            else
            {   
                data_tag=0;
                MPI_Send(&row,1,MPI_INT,rowstruct.procnum,data_tag,MPI_COMM_WORLD);
		//       MPI_Send(&row,1,MPI_INT,rowstruct.procnum,terminator_tag,MPI_COMM_WORLD);
                data_tag=1;
            }
	    for (num = 0; num < X_RESN; num++) {
	      if (rowstruct.foo[num] == 1) {
		  XDrawPoint (display, win, gc, num, rowstruct.rownum  );

	      }
	    }
	} while (count > 0);	      

	//      printf("after do-while in master\n");

	XFlush (display);
	sleep (5);
	
        printf("got to end of master\n");
    }
    else /* Slaves */
    {   
        int row = 0;

        /* Recieve the row number */
	MPI_Recv(&row,1,MPI_INT,0,data_tag,MPI_COMM_WORLD,&status);
        printf("row is %d in proc %d\n",row,myrank);
	rowstruct.rownum = row;

        while(data_tag)
        {
	    /* Calculate and draw points */
	    for(j=0; j < Y_RESN; j++) 
            {
                z.real = z.imag = 0.0;
                c.real = ((float) j - 400.0)/200.0;               /* scale factors for 800 x 800 window */
	        c.imag = ((float) rowstruct.rownum - 400.0)/200.0;
		//      printf("row num is %d\n",rowstruct.rownum);
                k = 0;

                do  /* Iterate for pixel color */
                {                                          
                    temp = z.real*z.real - z.imag*z.imag + c.real;
                    z.imag = 2.0*z.real*z.imag + c.imag;
                    z.real = temp;
                    lengthsq = z.real*z.real+z.imag*z.imag;
                    k++;
	    
                } while (lengthsq < 4.0 && k < 100);
		
	        if (k == 100)
		  rowstruct.foo[j] = 1;
		else
		  rowsturct.foo[j] = 0;
            }
	    
            rowstruct.procnum = myrank;
	    MPI_Send(&rowstruct,X_RESN+2,MPI_INT,0,msgtag,MPI_COMM_WORLD);
            MPI_Recv(&row,1,MPI_INT,0,data_tag,MPI_COMM_WORLD,&status);
            rowstruct.rownum=row;
        }    

        printf("got to end of slave %d\n",myrank);
    }
       
    MPI_Finalize();

    return 0;
	
    /* Program Finished */

}


