#include <parallel.h>
#include <stdio.h>
#include <math.h>
#include "rtd.h"
#include "macros.h"
#include "globals.h"

/* these definitions describe a window in the x-y plane
   that the whole thing is viewed through. */
#define INC  1.0
#define NUM_PROCS 4
#define PAGESIZE 1024
#define X_MIN 0.0
#define X_MAX 511.0
#define Y_MIN 0.0
#define Y_MAX 511.0

struct object_data *data; 
double sam = 1.0;
int xground, yground;
int     level;

struct sphere_data light_source;

struct barrier_area
         {
         char lock;
         char wait_lock;
         int procs_in;
         int height;
         };

struct shared_pointer 
         {
         char start_pad[PAGESIZE], start;
         char lock;
         char img[512][512];
         double ground[300][300];
         struct barrier_area barrier;
         char fin, end_pad[PAGESIZE];
         };

struct shared_pointer shared_info;
int id;

main (argc, argv)
int     argc;
char  **argv;
{
    FILE * df, *texfile, *fs, *viewpoint_file, *fp;
    char output_file_name[40];  
    static double   xco,
                    yco;
    struct ray  rr;
    struct vector   vp;
    double  x,
            y,
            z,
            view_x,
            view_y,
            view_z;
    int     i,
            in = 0,
            out = 0,
            tex = 0,
            view = 0;
    int x1, y1, z1;
    int     c, num_bytes = 512 * 512;
    double offset_x = 0.0,
           offset_y = 0.0;

/* command interp */

    for (i = 1; i < argc; i++) {
	if (argv[i][0] != '-')
	    booboo ("Options strt with a '-' bozo");
	c = argv[i][1];

	switch (c) {
	    case ('i'): 
		if (in)
		    booboo ("Sorry, but you may only have one input file");
		in = 1;
		if ((i + 1) >= argc || argv[i + 1][0] == '-')/* no arg */
		    df = stdin;
		else
		    if ((df = fopen (argv[++i], "r")) == NULL)
			booboo ("input file not found");
		break;
	    case ('o'): 
		if (out)
		    booboo ("Sorry, but you may have only one output file");
		out = 1;
		if ((i + 1) >= argc || argv[i + 1][0] == '-')/* no arg */
		    fp = stdout;
		else
                    strcpy(output_file_name, argv[++i]);
/*
		    fp = fopen (argv[++i], "w");
*/
		break;
	    case ('s'): 
		if (tex)
		    booboo ("Sorry, but you may have only one image file");
		if ((i + 1) >= argc || argv[i + 1][0] == '-')/* no arg */
		    booboo ("-s requires an argument");
		tex = 1;
		if ((texfile = fopen (argv[++i], "r")) == NULL)
		    booboo ("image file not found");
		break;
		booboo ("this line shouldn't do anything");
	    case ('S'): 
		if (argv[i][2] < '0' || argv[i][2] > '9'){
printf("%c\n",argv[i][2]);
		    booboo ("-S needs a numerical argument");}
		sam = atof (&(argv[i][2]));
		break;
            case ('v'):
                view = TRUE;
                if ((i + 1) >= argc || argv[i + 1][0] == '-')
                  booboo("-v requires an argument");
                if ((viewpoint_file = fopen(argv[++i], "r")) == NULL)
                  booboo ("viewpoint file not found");
                break;
	    default: 
		booboo ("Unrecognized option. Better try again");
	}
    }


    if (!in)
	if ((df = fopen ("bdata.i", "r")) == NULL)
	    booboo ("bdata.i not found");
    if (!out)
      strcpy(output_file_name, "data.dis");
/*
	fp = fopen ("data.dis", "w");
*/
    if (!tex)
	if ((texfile = fopen ("pat.def", "r")) == NULL)
	    booboo ("pat.def not found");
    if (view)
      {
      printf("reading viewpoint file\n");
      fscanf(viewpoint_file,"%F %F %F\n", &view_x, &view_y, &view_z);
      printf("view point x = %f y = %f z = %f\n", view_x, view_y, view_z);
      }
    else
        /* define viewpoint */
      {
      view_x = 256.0;
      view_y = 256.0;
      view_z = -600.0;
      };

    MV(view_x, view_y, view_z, vp);
    offset_x = view_x - ((X_MAX - X_MIN) / 2);
    
    init_global();
    init_seads(x_world_start, x_world_end, y_world_start, y_world_end,
               z_world_start, z_world_end);
    
    printf("finished initializing seads\n");

    g_bal (df);
    g_bod (texfile);


    printf ("%d %d\n", ((int) (X_MAX + 1.0)), ((int) (Y_MAX + 1.0)));
    share(&shared_info.start,
          &shared_info.fin - &shared_info.start);
    printf("shared area\n");
/* define light source (rad defines how fuzzy the shadows will be) */
    MV(0.0, 900.0, -200.0, light_source.cent);
    light_source.rad = 40;
    id = NUM_PROCS - 1;
    spinunlock(&shared_info.lock);
    shared_info.barrier.procs_in = 0;
    shared_info.barrier.height = NUM_PROCS;
    spinlock(&shared_info.barrier.wait_lock);
    spinunlock(&shared_info.barrier.lock);
    printf("forking off processors\n");
    for (i = 0; i < NUM_PROCS - 1; i++)
      if (fork() == 0)
        {
        id = i; 
        printf("start process %d\n", id);
        break;
        }

     for (y1 = id; y1 <= Y_MAX; y1+= NUM_PROCS)
     {
       for (x1 = X_MAX ; x1 >= 0; x1--)
         {
         xco = x1 * INC + offset_x;
         yco = y1 * INC + offset_y;
	    MV(xco, yco, 0.0, rr.org);
/* define the ray through a pixel and find out the value for that pixel */
	    SV(rr.dir, rr.org, vp);
            rr.src = 0;
	    shared_info.img[Y_MAX - y1][x1] = (char) shade(&rr, yco);
	}
/* put some info out so we can guess how long this all takes. */
/*	update (xco, X_MIN, X_MAX);*/
        printf("y= %d id=%d\n", y1, id);
    }
  printf("process %d waiting\n", id);
  bar();


  if (id!=NUM_PROCS-1) 
    { printf("process %d ending\n",id);
    exit(0);
    }

  if (id == NUM_PROCS - 1)
    {
    printf("printing image id= %d\n", id);
    fp = fopen(output_file_name, "w");
    fprintf (fp, "%d %d\n", (int) (X_MAX - X_MIN + 1.0), 
                            (int) (Y_MAX - Y_MIN + 1.0));
    printf("num bytes= %d\n", num_bytes);
    x1 = fwrite(shared_info.img, sizeof(char), num_bytes, fp);
    printf("number of bytes written = %d\n", x1);
    fclose(fp);
    };
  printf("process %d ending\n",id);
}  /* end of main */

bar()
  {
  spinlock(&shared_info.barrier.lock);
  shared_info.barrier.procs_in++;
  if (shared_info.barrier.procs_in < shared_info.barrier.height)
    {
    spinunlock(&shared_info.barrier.lock);
    spinlock(&shared_info.barrier.wait_lock);
    };
  if (shared_info.barrier.procs_in == 0)
    spinunlock(&shared_info.barrier.lock);
  else
    {
    shared_info.barrier.procs_in--;
    spinunlock(&shared_info.barrier.wait_lock);
    };
  } /* end of bar */

booboo (str)
char   *str; {
    printf ("%s\n", str);
    exit (-1);
}
