// supervisor code
#include <stdio.h>
#include "sig.h"
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <stdlib.h>

#define MAXN 1024

int n;
pid_t *pids; //pids[n] - waiter
pid_t gid;

void killall(void)
{
	int i;	
	for(i=0;i<=n;i++)
		kill(pids[i],SIGKILL);
}

void termh(int s)
{
	killall();
	exit(0);
}

char *params[MAXN];
int periods[MAXN][MAXN];
int pcounts[MAXN];
char h[MAXN][16];

int main(int argc, char** argv)
{
	int i;
	
	// minor init
	atexit(killall);
	for(i=0;i<MAXN;i++)
		params[i]=h[i];
	
	// read params
	printf("* Params...\n");
	FILE* f=fopen("./config.cfg","r");
	fscanf(f,"%d",&n);
	pids=malloc(n*sizeof(pid_t));

	// create table
	mkdir("table",0777);
	
	// block signals
	sigset_t ss;
	sigemptyset(&ss);
	sigaddset(&ss, SIGUSR1);
	sigaddset(&ss, SIGUSR2);
	sigaddset(&ss, SIGALRM);
	sigprocmask(SIG_BLOCK, &ss, 0);

	// handler
	signal(SIGTERM, termh);
	
	// create everybody
	printf("* Forking...\n");
	if(!(pids[n]=fork()))
	{
		char s[16];
		sprintf(s,"%d",n);
		execl((char*)"./server",(char*)"./server",(char*)s,(char*)0);
	}
	printf("* Waiter PID = %d\n",(int)pids[n]);
	for(i=0;i<n;i++)
	{
		fscanf(f,"%d",&pcounts[i]);
		int j;
		for(j=0;j<pcounts[i];j++)
			fscanf(f,"%d",&periods[i][j]);
		sprintf(h[0],"./phil");
		sprintf(h[1],"%d",(int)pids[n]);
		sprintf(h[2],"%d",i);
		for(j=0;j<pcounts[i];j++)
			sprintf(h[j+3],"%d",periods[i][j]);
		params[pcounts[i]+3]=NULL;
		if(!(pids[i]=fork()))
			execv("./phil",params);
		params[pcounts[i]+3]=h[pcounts[i]+3];
		printf("* Philosopher%d PID = %d\n",i,(int)pids[i]);
	}
	
	// set pgids
	gid=pids[0];
	for(i=0;i<n;i++)
		setpgid(pids[i],gid);
	
	// send sig4
	printf("* Sending SIG4...\n");
	for(i=0;i<n;i++)
		kill(pids[i],SIG4);
	
	// respawn cycle
	printf("* Cycling...\n");
	while(1)
	{
		pid_t dead=wait(0);
		if(dead==pids[n])
		{
			printf("! Waiter is dead! Closing...\n");
			break;
		}
		else
		{
			int k=-1;
			for(i=0;i<n;i++)
			{
				if(dead==pids[i])
				{
					k=i;
					break;
				}
			}
			if(k!=-1)
			{
				int j;
				printf("! Philosopher%d is dead! Respawning...\n",i);
				sprintf(h[0],"./phil");
				sprintf(h[1],"%d",(int)pids[n]);
				sprintf(h[2],"%d",k);
				for(j=0;j<pcounts[k];j++)
				sprintf(h[j+3],"%d",periods[k][j]);
				params[pcounts[i]+3]=NULL;
				if(!(pids[i]=fork()))
					execv("./phil",params);
				setpgid(pids[i],gid);
				params[pcounts[i]+3]=h[pcounts[i]+3];
				kill(pids[i],SIG4);
				printf("* Philosopher%d PID = %d\n",i,(int)pids[i]);
			}
		}
	}
	return 0;
}
