#include "pvm_test.h"
#include "module_list.h"


main(argc,argv)
int	argc;
char  **argv;
{
char	myversion[25];
char	*myarch;
char	myhostname[MAX_HOST_NAME_LENGTH];
int	test_num;				/* Current test module processed 		*/
int	num_hosts=1;				/* Number of hosts (not including this one) 	*/
FILE    *infile = NULL;				/* input file 					*/
char	outfilename[OUTFILE_MAX_LENGTH];	/* Name of output file				*/
int	mytid;					/* PVM tid					*/
int	num_diff_arch;				/* Number of different data format		*/
int	shuffle[MAX_HOST];			/* Array of shuffled index of hostpool		*/
int	sub_shuffle_pool[MAX_HOST];		/* Subset of shuffle			 	*/
int 	i,j,k;					/* Loop indices					*/
int 	req;					/* Num of hosts required for the current test	*/
int	num_wanted;				/* Number of hosts wanted after a test		*/
int	num_wanted_ef;				/* Actual number of hosts wanted		*/
int	status;					/* Temporary status of a test			*/
int	index;					/* Size of window in shuffle			*/
int	info;					/* Dummy variable to keep track of return values*/
char	name1[25];				/* Name of the output file for test 45		*/
char 	name2[25];				/* Name of the output file for test 46		*/
extern void term();				/* Interruption handler 			*/



/************************************************/
/*	Miscelleanous Initialisation	      	*/
/************************************************/

/*****	Set stdout and stderr		*****/

dup2(fileno(stdout),2);
setbuf(stdout,NULL);

/*****  Parse the arguments     	*****/
if (argc != 2)
        {
        fprintf(stderr,"Usage: %s <input file> \n",argv[0]);
        exit(1);
        }

/*****	Get PVM_ARCH			*****/
if((myarch = getenv("PVM_ARCH"))== NULL)
	{
	fprintf(stderr,"\tThe PVM_ARCH environment variable should be set \n");
	exit(1);
	}

/***** Get name of this host            *****/
if (gethostname(myhostname,MAX_HOST_NAME_LENGTH) == -1)
        {
        fprintf(stderr,"\tgethostname() call failed");
        exit(1);
        }

/***** Get version of PVM on this host *****/
if (pvm_version() == NULL)
	{
	fprintf(stderr,"\tpvm_version() : Failed\n");
	exit(1);
	}
	
strcpy(myversion,pvm_version());


strcpy(hostpool[0]=(char*)malloc(sizeof(char)*strlen(myhostname)+1),myhostname);
strcpy(hostarch[0]=(char*)malloc(sizeof(char)*strlen(myarch)+1),myarch);

/***** Test structure initialisation 	*****/
	masters = (module_array *)module_list;

/***** Setting the default parameters   *****/

messages_length 	= MESSAGES_LENGTH_DEFAULT;
max_size 		= MAX_SIZE_DEFAULT;
incr 			= INCR_DEFAULT;
start_size 		= START_SIZE_DEFAULT;
num_messages 		= NUM_MESSAGES_DEFAULT;
all_combos 		= ALL_COMBOS_DEFAULT; 
timing_average		= TIMING_AVERAGE_DEFAULT;
timing_total		= TIMING_TOTAL_DEFAULT;

all_tests		= ALL_TESTS_DEFAULT;
all_messaging		= ALL_MESSAGING_DEFAULT;
all_routine		= ALL_ROUTINE_DEFAULT;
all_funnel_nodata	= ALL_FUNNEL_NODATA_DEFAULT;
all_funnel_data		= ALL_FUNNEL_DATA_DEFAULT;
all_head_nodata		= ALL_HEAD_NODATA_DEFAULT;
all_head_data		= ALL_HEAD_DATA_DEFAULT;
all_triangle_nodata	= ALL_TRIANGLE_NODATA_DEFAULT;
all_triangle_data	= ALL_TRIANGLE_DATA_DEFAULT;
all_perf		= ALL_PERF_DEFAULT;

/***** Input file parsing 		*****/
input_parse(infile,argv[1],&num_hosts,myhostname,outfilename);

/***** Welcome message  *****/

fprintf(outfile,"------------------------------------\n");
fprintf(outfile,"PVM tester --- version 2.0\n");
fprintf(outfile,"------------------------------------\n");

/***** check Parameters *****/

if (start_size > max_size)
	{
	start_size = max_size;
	fprintf(stdout,"\t Warning : Minimum size > Maximum size\n");
	}

/***** Update Tests Setting		*****/

if (all_tests == 1)
	for (i=0;i<NUMBER_OF_TESTS;i++)
		(*masters)[i].flag.perform = 1;
if (all_messaging == 1)
	for (i=47;i<NUMBER_OF_TESTS;i++)
		(*masters)[i].flag.perform = 1;
if (all_routine == 1)
	{
	for (i=0;i<44;i++)
		(*masters)[i].flag.perform = 1;
	(*masters)[46].flag.perform = 1;
	}
if (all_funnel_nodata == 1)
	for (i=79;i<93;i++)
		(*masters)[i].flag.perform = 1;
if (all_funnel_data == 1)
	for (i=93;i<NUMBER_OF_TESTS;i++)
		(*masters)[i].flag.perform = 1;
if (all_head_nodata == 1)
	for (i=47;i<55;i++)
		(*masters)[i].flag.perform = 1;
if (all_head_data == 1)
	for (i=55;i<63;i++)
		(*masters)[i].flag.perform = 1;
if (all_triangle_nodata == 1)
	for (i=63;i<71;i++)
		(*masters)[i].flag.perform = 1;
if (all_triangle_data == 1)
	for (i=71;i<79;i++)
		(*masters)[i].flag.perform = 1;
if (all_perf == 1)
	{
	(*masters)[44].flag.perform = 1;
	(*masters)[45].flag.perform = 1;
	}

/***** Possible output files		*****/
if ((*masters)[44].flag.perform == 1)
        {
 	if (outfile == stdout)
		{
	        sprintf(name1,"%s.%d",OUT45,getpid());
       	 	if ((out45=fopen(name1,"w"))==NULL)
       	         	{
                	fprintf(stderr,"\tfopen() Failed to open %s\n",OUT45);
                	exit(1);
                	}
		}
	else
		out45 = outfile;
        }
if ((*masters)[45].flag.perform == 1)
        {
	if (outfile == stdout)
		{
        	sprintf(name2,"%s.%d",OUT46,getpid());
        	if ((out46=fopen(name2,"w"))==NULL)
                	{
                	fprintf(stderr,"\tfopen() Failed to open %s\n",OUT46);
                	exit(1);
                	}
		}
	else
		out46 = outfile;
        }

/***** Set handlers 			*****/
signal(SIGINT,term);
signal(SIGTERM,term);

/***** Compute my tid 			*****/
if ((mytid = pvm_mytid())<0)
	{
	fprintf(outfile,"\tCannot contact local demon \n");
	term(HIGH_LEVEL);
	}
/***** Disable pvm error messages       *****/
info = pvm_setopt(PvmAutoErr,0);
if (info <0)
        {
        fprintf(outfile,"\tpvm_setopt() : Failed with error %d\n",info);
        fprintf(outfile,"\tSome extra messages will appear\n");
        }

/***** Start Group Server		*****/
if (start_group_server() == -1)
	term (HIGH_LEVEL);

/***** Check hosts 			*****/
if (check_hosts(num_hosts) == -1)
	term(HIGH_LEVEL);

/***** Check Version 			*****/
info = check_version(num_hosts,myversion);
if (info == -1)
	term(HIGH_LEVEL);
/***** Get all arch			*****/
if (get_all_arch() == -1)
	term(HIGH_LEVEL);
/***** Get number of different arch	*****/
if ((num_diff_arch = get_num_diff_arch(num_hosts)) <0)
	{
	fprintf(outfile,"\tUnable to compute the number of different architeccture\n");
	term(HIGH_LEVEL);
	}
/***** Compute the shuffle		*****/
if (find_shuffle(num_hosts,num_diff_arch,shuffle) <0)
	{
	fprintf(outfile,"\tUnable to compute the shuffle\n");
	exit(1);
	}
/***** Remove all hosts 		*****/
if (remove_all_hosts() == -1)
	term(HIGH_LEVEL);
/***** Printout Configuration 		*****/
print_out_misc(myversion,num_hosts,argv[1],outfilename);

/************************************************/
/* 		Main loop 		      	*/
/************************************************/
for (test_num=0;test_num< NUMBER_OF_TESTS;test_num++)
	{
	if ((*masters)[test_num].flag.perform == 1)
		{	/*	We perform this test		*/
		fprintf(outfile,"test#%d: %s\n",test_num+1,(*masters)[test_num].description);
		req = (*masters)[test_num].num_req_hosts;
		num_wanted = (*masters)[test_num].flag.after_hosts;
		if (req == ALL_HOSTS)
			req = num_hosts;
		if (req == ALL_ARCHS)
			req = num_diff_arch+1;
		if (req >num_hosts)
			req = num_hosts;
		if (num_wanted == ALL_HOSTS)
                        num_wanted = num_hosts;
                if (num_wanted == ALL_ARCHS)
                        num_wanted = num_diff_arch+1;
                if (num_wanted >num_hosts)
                        num_wanted = num_hosts;
		if ((req > num_diff_arch)||(req == 1)||(req>=num_hosts)||(all_combos == 0))
			/****** No shuffling Problems ******/

			{
			if (allocate(shuffle,req,&num_wanted) <0)
				{	/* The allocation didn't succeed	*/
				fprintf(outfile,"\tAllocation failed for some hosts\n");
				(*masters)[test_num].status = NOT_COMPLETED;
				if (remove_all_hosts() <0)
					{       /* Cannot remove hosts  */
					fprintf(outfile,"\tCannot delete hosts\n");
					term(HIGH_LEVEL);
					}	
				}
			else		/* We do the test */
				{
				status = (*masters)[test_num].proc_master(shuffle,req);
				if (status == NOT_POSSIBLE)
					{
					(*masters)[test_num].status=PASSED;
					fprintf(outfile,"\tNot_possible for architecture combination :\n");
					fprintf(outfile,"\t%s |  ",myarch);
					for (k=1;k<req;k++)
						fprintf(outfile," %s ",hostarch[shuffle[k]]);
					for (k=req;k<(*masters)[test_num].num_req_hosts;k++)
						fprintf(outfile," %s ",hostarch[shuffle[k%req]]);
					fprintf(outfile,"\n");
					}
				if(status == PASSED)
					(*masters)[test_num].status=PASSED;
				if (status == FAILED)
					(*masters)[test_num].status=FAILED;	
				if ((info = unexpected_host_killed(num_wanted-1)) == -1)
					{
					fprintf(outfile,"\tNot the right number of hosts after this test\n");
					(*masters)[test_num].status = NOT_COMPLETED;
					}	
				if (info == -2)
					{
					fprintf(outfile,"\tFailure of checking function\n");
					(*masters)[test_num].status = NOT_COMPLETED;
					}	
				if (remove_all_hosts() <0)
                                	{       /* Cannot remove hosts  */
                                	fprintf(outfile,"\tCannot delete hosts\n");
                                	term(HIGH_LEVEL);
                                	}
				print_test_result(test_num);
				}
			}
		else
			/***** We must try all the combinations *****/
			{
			sub_shuffle_pool[0]=shuffle[0];
			(*masters)[test_num].status = PASSED;
			for (i=0;i<num_diff_arch-req+2;i++)
				{
				sub_shuffle_pool[1]=shuffle[i+1];
				if (req==2)
					index = 1;
				else
					index = num_diff_arch-req-i+2;
				for (j=0;j<index;j++)
					{
					num_wanted_ef = num_wanted;
					for(k=1;k<req-1;k++)
						sub_shuffle_pool[k+1] = shuffle[i+j+k+1];
					if (allocate(sub_shuffle_pool,req,&num_wanted_ef) <0)
						{	/* The allocation didn't succeed        */
						fprintf(outfile,"\tAllocation failed for some hosts\n");
                                		(*masters)[test_num].status = NOT_COMPLETED;	
						if (remove_all_hosts() < 0)
							{/* 	Cannot remove hosts	*/
							fprintf(outfile,"\tCannot remove hosts\n");
							term(HIGH_LEVEL);
							}
						}
					else	/* We do the test	*/
						{
						status = (*masters)[test_num].proc_master(sub_shuffle_pool,req);
						if (status == FAILED)
							{
							(*masters)[test_num].status = FAILED;
							fprintf(outfile,"\tFailed for architecture combination : ");
							fprintf(outfile,"\t%s ",myarch);
							for (k=1;k<req;k++)	
								fprintf(outfile," %s ",hostarch[sub_shuffle_pool[k]]);
							fprintf(outfile,"\n");
							}	
						if (status == NOT_POSSIBLE)
							{
							fprintf(outfile,"\tNot_possible for architecture combination :");
							fprintf(outfile,"%s | ",myarch);
							for (k=1;k<req;k++)
								fprintf(outfile," %s ",hostarch[sub_shuffle_pool[k]]);
							for (k=req;k<(*masters)[test_num].num_req_hosts;k++)
								fprintf(outfile," %s ",myarch);
							fprintf(outfile,"\n");
							}	
						if (unexpected_host_killed(num_wanted_ef-1) <0 )
							{
                                        		fprintf(outfile,"\tSome hosts has unexpectedly died\n");
                                        		(*masters)[test_num].status = FAILED;
                                        		}
						if (remove_all_hosts() <0)
                                        		{       /* Cannot remove hosts  */
                                        		fprintf(outfile,"\tCannot delete hosts \n");
                                        		term(HIGH_LEVEL);
                                        		}
						}
					}
				}		
			print_test_result(test_num);
			}	
		}
	}
term(OK_LEVEL);
}
