/*
  Sean Dobbs
  Period 4
  Missle trajectory simulation with pvm
*/

#include <iostream.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "glaux.h"
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glut.h"
#include "/usr/pvm3/include/pvm3.h"

// Constants
const int kMaxSlaves = 25;
#define kSlaveName "wallslave"

// Globals
struct Wall
{
	 int x, y, height;
};

static int dist, range, numwalls, nslaves, *tids;
static Wall *walls;

// Functions
static void Init(void)
{
	glClearColor(0.0, 0.0, 0.0, 1.0);
	glShadeModel( GL_FLAT );
	glOrtho(0.0, 1000.0, 0, 90.0, -5.0, 5.0);
}

static void display()
{
	double v=0, vback, y;
	int numt;
	char databack[455];
	glClear( GL_COLOR_BUFFER_BIT );
	cout<<"target distance: ";
	cin>>dist;
	cout<<"hit range: ";
	cin>>range;
	cout<<"number of walls: ";
	cin>>numwalls;
	if(numwalls > 0)
	{
		 walls = new Wall[numwalls];
		 for(int i=0; i<numwalls; i++)
		 {
			  cout<<"position (x y): ";
			  cin>>walls[i].x>>walls[i].y;
			  cout<<"height: ";
			  cin>>walls[i].height;
		 }
	}
	glBegin(GL_POINTS);
	while(v<=1000)
	{
		 // start up slave tasks 
		 numt=pvm_spawn(kSlaveName, (char**)0, 0, "", nslaves, tids);
		 if( numt < nslaves )
		 {
			  cout<<"Trouble spawning slaves. Aborting. Error codes are:"<<endl;
			  for(int i=numt; i<nslaves; i++) 
				   cout<<"TID "<<i<<" "<<tids[i]<<endl;
			  for(int i=0; i<numt; i++)
				   pvm_kill(tids[i]);
			  pvm_exit();
			  exit(0);
		 }	 

		 for(int j=0;j<nslaves;j++)
		 {
			  pvm_initsend(PvmDataDefault);     // Get ready to send message buffer
			  pvm_pkdouble(&v, 1, 1);
			  pvm_pkint(&dist, 1, 1);
			  pvm_pkint(&range, 1, 1);
			  pvm_pkint(&numwalls, 1, 1);
			  if(numwalls>0)
			  {
				   for(int i=0; i<numwalls; i++)
				   {
						pvm_pkint(&(walls[i].x), 1, 1);
						pvm_pkint(&(walls[i].y), 1, 1);
						pvm_pkint(&(walls[i].height), 1, 1);
				   }
			  }
			  pvm_send(tids[j], 0);
//			  cout<<"sent v="<<v<<endl;
			  v+=.5;
		 }
		 for(int j=0;j<nslaves;j++)
		 {
			  pvm_recv( -1, 5 );
			  pvm_upkdouble(&vback, 1, 1);
			  pvm_upkbyte(databack, 455, 1);
			  if(vback<=1000)
			  {
				   for(int k=0;k<5;k++)
				   {
						y=0.0;
						for(int i=0;i<455;i++)
						{
							 if(databack[i]==k)
							 {
								  switch(databack[i])
								  {
								  case 1: glColor3f(0.0, 0.0, 1.0); break;
								  case 2: glColor3f(0.0, 0.0, 0.8); break;
								  case 3: glColor3f(0.0, 0.0, 0.7); break;
								  case 4: glColor3f(0.0, 0.0, 0.6); break;
								  case 5: glColor3f(0.0, 0.0, 0.5); break;
								  default: glColor3f(0.0, 0.0, 0.0); break;
								  }
								  if(databack[i]!=0) glVertex3f(vback, y, 0.0);
							 }
							 y += 0.2;
						}
				   }
			  }
//			  cout<<"got v="<<vback<<endl;
		 }
	}
	glEnd();
	glFlush();
	glutPostRedisplay();
	pvm_exit();
//	exit(0);
}

static void Reshape( int width, int height )
{
	 glClear( GL_COLOR_BUFFER_BIT );
	 glViewport(0, 0, (GLint)width, (GLint)height);
	 glMatrixMode( GL_PROJECTION );
 	 glLoadIdentity();
	 glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char **argv)
{
	 int mytid, nhost, narch;

	 glutInit(&argc, argv);
	 glutInitDisplayMode( GLUT_SINGLE | GLUT_RGB );
	 glutInitWindowSize(600, 270);
	 glutInitWindowPosition(50,250);
	 glutCreateWindow(argv[0]);
	 Init();
	 glutDisplayFunc(display);
	 glutReshapeFunc(Reshape);
	 
	 mytid = pvm_mytid();  // start up pvm
	 if( pvm_parent() == PvmNoParent )  // set number of slaves to run 
	 {
		  cout<<"How many slave programs?: ";
		  cin>>nslaves;
		  if( nslaves > kMaxSlaves ) nslaves = kMaxSlaves;
	 }
	 else
	 {
		  pvm_exit();
		  exit(0);
	 }
	 // init some variables
	 tids = new int[nslaves];
	 glutMainLoop();
	 return 0;	
}
