// waiter code
#include <stdio.h>
#include "sig.h"
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdlib.h>

int n, *forks, *wanttoeat, *eating;
pid_t *pids;

volatile int forksneeded=0;
volatile int forksfree=0;

void display(void)
{
	int i;
	for(i=0;i<=n;i++)
		if(forks[i%n])
			printf("Y ");
		else
			printf("_ ");
	printf("\n");
	for(i=0;i<n;i++)
		if(eating[i])
			printf(" Y");
		else if(wanttoeat[i])
			printf(" O");
		else 
			printf(" ?");
	printf("\n");
}

void giveforksh(int s)
{
	forksneeded=1;
}

void freeforksh(int s)
{
	forksfree=1;
}


void giveforks(void)
{
	struct dirent *dd;
	DIR* d=opendir("./table");
	while((dd=readdir(d))!=0)
	{
		if(dd->d_name[0]=='h')
		{
			char hname[14]="";
			sprintf(hname,"./table/%s",dd->d_name);
			int pn;
			sscanf(hname,"./table/h%d",&pn);
			int fd=open(hname, O_RDONLY);
			read(fd, &pids[pn], sizeof(pid_t));
			close(fd);
			unlink(hname);
			if(eating[pn] || (forks[pn] && forks[(pn+1)%n]))
			{
				forks[pn]=0;
				forks[(pn+1)%n]=0;
				eating[pn]=1;
				kill(pids[pn],SIG2);
			}
			else
				wanttoeat[pn]=1;
		}
	}
	closedir(d);
	display();
}

void freeforks(void)
{
	struct dirent *dd;
	DIR* d=opendir("./table");
	int q=0;
	while((dd=readdir(d))!=0)
	{
		if(dd->d_name[0]=='f')
		{
			char hname[14]="";
			sprintf(hname,"./table/%s",dd->d_name);
			int pn;
			sscanf(hname,"./table/f%d",&pn);
			unlink(hname);
			forks[pn]=1;
			forks[(pn+1)%n]=1;
			eating[pn]=0;
			q++;
		}
	}
	closedir(d);
	if(q>0)
	{
		int i;
		for(i=0;i<n;i++)
		{
			if(wanttoeat[i] && forks[i] && forks[(i+1)%n])
			{
				forks[i]=0;
				forks[(i+1)%n]=0;
				eating[i]=1;
				wanttoeat[i]=0;
				kill(pids[i],SIG2);
			}
		}
	}
	display();
}


int main(int argc, char** argv) // philosophers count, 
{
	// ==========================  Initialize  ========================== //
	// block everything
	sigset_t sset;
	sigemptyset(&sset);
	sigaddset(&sset,SIG1);
	sigaddset(&sset,SIG3);
	sigprocmask(SIG_BLOCK, &sset, 0);
	
	// create masks for sigsuspend
	sigprocmask(SIG_BLOCK, 0, &sset);
	sigset_t sig13set=sset;
	sigdelset(&sig13set,SIG1);
	sigdelset(&sig13set,SIG3);
	
	// command line params
	int i; // n-th philosopher needs n-th and n+1-th forks
	sscanf(argv[1],"%d",&n); 
	forks=(int*)malloc(n*sizeof(int));
	wanttoeat=(int*)malloc(n*sizeof(int));
	eating=(int*)malloc(n*sizeof(int));
	pids=(pid_t*)malloc(n*sizeof(pid_t));
	for(i=0;i<n;i++)
	{
		forks[i]=1;
		wanttoeat[i]=0;
		eating[i]=0;
	}

	// set signal handlers
	signal(SIG1, giveforksh);
	signal(SIG3, freeforksh);
		
	// =========================  Life Cycle  ============================//
	printf("W Waiter Ready.\n");fflush(stdout);
	while(1)
	{
		sigsuspend(&sig13set); //may contain bug...

		if(forksneeded)
			giveforks();

		if(forksfree)
			freeforks();
	}
	return 0;
}
