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

volatile int hasbegun=0;
volatile int timetoeat=0;
volatile int haveforks=0;
volatile int finisheat=0;

pid_t opid;
pid_t spid;
int selfn;

void hbegin(int s)
{
	hasbegun=1;
}

void htimetoeat(int s)
{
	timetoeat=1;
}

void hgetforks(int s)
{
	haveforks=1;
}

void hfinisheat(int s)
{
	finisheat=1;
}


int main(int argc, char** argv) // officiant pid, self numb, timing...
{
	// ========================  Initialize  ============================ //
	// block everything
	sigset_t sset;
	sigemptyset(&sset);
	sigaddset(&sset, SIG4);
	sigaddset(&sset, SIG2);
	sigaddset(&sset, SIGALRM);
	sigprocmask(SIG_BLOCK, &sset, 0);
	
	// create masks for sigsuspend
	sigprocmask(SIG_BLOCK, 0, &sset);
	sigset_t sig2set=sset;
	sigset_t sig4set=sset;
	sigset_t sigalrmset=sset;
	sigdelset(&sig2set,SIG2);
	sigdelset(&sig4set,SIG4);
	sigdelset(&sigalrmset,SIGALRM);

	// set sig2 handler  [eat!]
	signal(SIG2,hgetforks);

	// command line params
	int* timing=malloc(sizeof(int)*argc);
	int i,n=argc-3;
	sscanf(argv[1],"%d",&opid);
	sscanf(argv[2],"%d",&selfn);
	for(i=3;i<argc;i++)
		sscanf(argv[i],"%d",&timing[i-3]);
	spid=getpid();

	// create temp file names
	char hname[14]="";
	char fname[14]="";
	sprintf(hname,"table/h%d",selfn);
	sprintf(fname,"table/f%d",selfn);
	
	// Wait for SIG4 [begin]
	signal(SIG4,hbegin);
	while(!hasbegun)
		sigsuspend(&sig4set);

	
	// ==========================  Life cycle  ========================== //
	printf("P%d Ready. Waiter PID = %d.\n",selfn,(int)opid);
	fflush(stdout);
	int p=0;
	int fd;
	struct itimerval tv;
	while(1)
	{
		// think a bit
		timetoeat=0;
		tv.it_value.tv_sec=0;
		tv.it_value.tv_usec=timing[p++]*100000;
		tv.it_interval.tv_sec=0;
		tv.it_interval.tv_usec=0;
		timetoeat=0;
		signal(SIGALRM,htimetoeat);
		setitimer(ITIMER_REAL,&tv,0);
		//printf("P%d Thinking for %d decosecs.\n",selfn,timing[p-1]);
		//fflush(stdout);
		while(!timetoeat)
			sigsuspend(&sigalrmset);
		
		//wait for forks
		haveforks=0;
		fd=open(hname,O_CREAT|O_WRONLY,0666);
		write(fd, &spid, sizeof(pid_t));
		close(fd);
		kill(opid,SIG1);
		//printf("P%d After thinking for %d decosecs came to a conclusion: Time to eat.\n",selfn,timing[p-1]);
		//fflush(stdout);
		while(!haveforks)
			sigsuspend(&sig2set);
	
		// eat
		finisheat=0;
		tv.it_value.tv_sec=0;
		tv.it_value.tv_usec=timing[p++]*100000;
		tv.it_interval.tv_sec=0;
		tv.it_interval.tv_usec=0;
		signal(SIGALRM,hfinisheat);
		setitimer(ITIMER_REAL,&tv,0);
		//printf("P%d Eating for %d decosecs.\n",selfn,timing[p-1]);
		//fflush(stdout);
		while(!finisheat)
			sigsuspend(&sigalrmset);		
		
		// give forks back
		fd=open(fname,O_CREAT|O_WRONLY,0666);
		write(fd, &spid, sizeof(pid_t));
		close(fd);
		kill(opid,SIG3);

		// p cycle
		p=p%n;
	}
	return 0;
}




