#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include "lottery.h"

/* This program tests the functionality of the setLotteryTickets
   system call. It also tests to make sure the number of tickets
   assigned in the system is properly updated by process creation
   and deletion.

   There are a total of 8 tests made.
   
   Also, it is important to notice that some tests are dependent
   on the success of previous tests.*/

void printresult( int, int );

void main( int argc, char *argv )
{
	int rval;		/* return value from system calls */
	int total;		/* total number of tickets in system */
	int prev;		/* used to hold various values from previous tests */
	int fail;		/* indicates one or more tests failed */

	int parent;		/* current/parent pid number */
	int child;		/* child pid number */

	/* initialize variables */

	total  = getTotalTickets();
	parent = getpid();
	fail   = 0;

	printf( "\n" );

	/* -------------------------------------------------------------
	 * TEST 1
	 * -------------------------------------------------------------
	 * Assign 10 tickets to current process. Then rval should be 10,
	 * and total should increase by 9 (since the current process
	 * already accounts for one ticket).
	 * ------------------------------------------------------------- */

	prev  = total;
	rval  = setLotteryTickets( parent, 10 );
	total = getTotalTickets();

	if( rval != 10 || prev + 9 != total )
	{
		fail = 1;
		printresult( 1, 1 );
	}
	else
		printresult( 1, 0 );

	/* -------------------------------------------------------------
	 * TEST 2
	 * -------------------------------------------------------------
	 * Attempt to assign 10 tickets to a nonexistent process. Then
	 * rval should be -1, and total should not change.
	 * ------------------------------------------------------------- */
	 
	prev  = total;
	rval  = setLotteryTickets( -1, 10 );
	total = getTotalTickets();
	 
	if( rval != -1 || prev != total )
	{
		fail = 1;
		printresult( 2, 1 );
	}
	else
		printresult( 2, 0 );

	/* -------------------------------------------------------------
	 * TEST 3
	 * -------------------------------------------------------------
	 * Assign 256 tickets to current process. Then rval should be
	 * 256 - ( total - 10 ) since the current process should get all
	 * available tickets remaining, including the 10 the process
	 * should already have. The value of total should be 256.
	 * ------------------------------------------------------------- */

	prev  = total;
	rval  = setLotteryTickets( parent, 256 );
	total = getTotalTickets();
		
	if( rval != 256 - ( prev - 10 ) || total != 256 )
	{
		fail = 1;
		printresult( 3, 1 );
	}
	else
		printresult( 3, 0 );

	/* -------------------------------------------------------------
	 * TEST 4
	 * -------------------------------------------------------------
	 * Attempt to fork. This should fail, since there should be no
	 * more tickets left in the system. Total tickets should not
	 * change.
	 * ------------------------------------------------------------- */
	 
	prev  = total;
	rval  = fork();
	total = getTotalTickets();
	 
	if( rval != -1 || prev != total )
	{
		if( rval != 0 )
		{
			fail = 1;
			printresult( 4, 1 );
		}
		else
			return;
	}
	else
		printresult( 4, 0 );

	/* -------------------------------------------------------------
	 * TEST 5 AND 6
	 * -------------------------------------------------------------
	 * Assign 10 tickets to current process, and attempt to fork.
	 * This time fork should succeed, rval should be 10, and total
	 * should be increased by 1.
	 * ------------------------------------------------------------- */

	rval  = setLotteryTickets( parent, 10 );
	total = getTotalTickets();
	child = fork();
		
	if( child == -1 || rval != 10 )
	{
		fail = 1;
		printresult( 5, 1 );
	}
	else if( getpid() == parent )
	{
		prev  = total;
		total = getTotalTickets();

		printresult( 5, 0 );
		
		if( prev + 1 != total )
		{
			fail = 1;
			printresult( 6, 1 );
		}
		else
			printresult( 6, 0 );
	}
	else /* keep child alive for now */
	{
		while( 1 ) { sleep( 1 ); }
		return;
	}
	
	/* -------------------------------------------------------------
	 * TEST 7
	 * -------------------------------------------------------------
	 * Assign 256 tickets to the child process, and attemp to assign
	 * 256 tickets to parent process. The total tickets should be
	 * 256. The return of the second call should be 10 (since that
	 * is how many the parent had, and no more can be granted).
	 * ------------------------------------------------------------- */	
	
	rval  = setLotteryTickets( child, 256 );
	rval  = setLotteryTickets( parent, 256 );
	total = getTotalTickets();
	
	if( rval != 10 || total != 256 )
	{
		fail = 1;
		printresult( 7, 1 );
	}
	else
		printresult( 7, 0 );

	/* -------------------------------------------------------------
	 * TEST 8
	 * -------------------------------------------------------------
	 * Kill child process, and attempt to assign 100 tickets to
	 * the parent process. This should work since the child's 
	 * tickets are returned to the system.
	 * ------------------------------------------------------------- */	
	
	rval  = kill( child, SIGKILL );

	prev  = total;
	total = getTotalTickets();
	rval  = setLotteryTickets( parent, 100 );
	
	if( rval != 100 || prev <= total )
	{
		fail = 1;
		printresult( 8, 1 );
	}
	else
		printresult( 8, 0 );

	/* -------------------------------------------------------------
	 * OUTPUT FINAL RESULT
	 * ------------------------------------------------------------- */		

	if( fail == 1 )
	{
		printf( "\n final result: [ fail ]\n\n" );
		return;
	}
	else
	{
		printf( "\n final result: [ okay ]\n\n" );
		return;
	}
}

/* small function to print test results */
void printresult( int test, int fail )
{
	if( fail == 1 )
		printf( " test #%d...... [ fail ]\n", test );
	else
		printf( " test #%d...... [ okay ]\n", test );
}
