/* 
 * File:   main.cpp
 * Author: lindsey
 *
 * Created on September 28, 2011, 3:48 PM
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <math.h>
#include <string.h>
#include <pthread.h>
typedef struct {
  float x;
  float y;
  float r;
  float color[3];
} circle2d;

typedef struct {
  float r;
  float g;
  float b;
} pixel;

int height,width,cirCnt;
pixel * image;
circle2d * circles;
int threadCount = 4;
int writePPM(const char * filename,int width, int height , pixel * pixels);

void * calculate(void * ptr)
{
    int threadNumber = *((int *) ptr);
	  int x,y,xStart, xEnd;

     xEnd = width  * (threadNumber + 1)/ threadCount; 
     xStart = width  * (threadNumber )/ threadCount; 
     



    for ( y = 0 ; y< height;y++)
      for ( x = xStart ; x< xEnd;x++){
	int i;
	int index = y*width + x;
	float dist;
	float colorval;
  
	for(i = 0;i< cirCnt; i++){
		dist = sqrt( (x - circles[i].x) * (x - circles[i].x) + (y - circles[i].y) * (y - circles[i].y) );
		if (dist<circles[i].r){
			colorval = 1 - (dist / circles[i].r);
			image[index].r =image[index].r +  colorval  * circles[i].color[0];
			image[index].g =image[index].g +  colorval  * circles[i].color[1];
			image[index].b =image[index].b +  colorval  * circles[i].color[2];
		}
	}
	  }

}
int main(int argc, char** argv) {
  width = 500,height = 500;
  cirCnt = 100;
  
  if (argc >= 2) cirCnt = atoi(argv[1]);
  if (argc >= 3) width  = atoi(argv[2]);
  if (argc >= 4) height = atoi(argv[3]);
  if (argc >= 5) threadCount = atoi(argv[4]);

  if (width <= 0 || height  <= 0 || cirCnt  <= 0){
	  printf("arguments must be a positive integer");
	  exit(1);
  } else {
	  printf("Rendering %d circles on a %dx%d image using %d threads\n", cirCnt, height, width, threadCount);
  }
  
  int totalSize= height*width;
  image = (pixel *)malloc (sizeof(pixel) * width * height );


  // randomly generate some spheres
  srand(1);		// seed the generation of random spheres for evauluating time
    
  circles = (circle2d *)malloc ( sizeof(circle2d) * cirCnt);
  int i;
  for (i = 0; i < cirCnt;i++){
    circles[i].x = drand48() * width;
    circles[i].y = drand48() * height;
    circles[i].r = drand48() * 100;
    circles[i].color[0] = drand48() / (cirCnt/100);
    circles[i].color[1] = drand48() / (cirCnt/100);
    circles[i].color[2] = drand48() / (cirCnt/100);
  }

  memset(image, 0,sizeof(pixel) * totalSize);
	int tid[threadCount], t; 
	pthread_t thread[threadCount];
	
	for (t = 0; t < threadCount;t++){
		tid[t] = t;
		pthread_create( &thread[t], NULL, calculate, (void *) &tid[t] );
	}
	for (t = 0; t < threadCount;t++)
		pthread_join(thread[t], NULL);
		
  writePPM("Thread Image.ppm",width, height, image);

  return 0;
}

	int writePPM(const char * filename,int width, int height , pixel * image){
		float * pixels = (float *) image;
	  FILE * fp = fopen (filename , "w");
	  int i;

	  if (fp == NULL) {
		fprintf(stderr , "unable to write to '%s'\n" , filename );
		return 0;
	  }

	  fprintf(fp , "P3\n" );
	  fprintf(fp , "%d %d\n" ,width , height);

	  fprintf(fp , "255 " );



	  // write pixels
		int color;
		int index;
		int r,c,cc;
			for(r = 0 ;  r < width ; r++ ) {
				for(c = 0 ;  c < height; c++ ) {
					for(cc = 0 ;  cc < 3; cc++ ) {
						
						index = r *width * 3 + 3 * c + cc;
						
						color = (int)(pixels[index] * 255);
						if (color > 255) color = 255;
						if (color < 0) color = 0;

						fprintf(fp , "%d " , color );
					}
				}
				fprintf(fp , "\n");
			}

	  fclose(fp);
	  return 1;
	}
