/*****************************************************************************
* 	Project 	: Network Based Message Queue System		    **
*	Course		: CIS 650 - Software Engineering		    **
*	Location 	: ~sameer/cis650/proj/con                 	    **
*	File		: con.cc	       	       			    **
*	Description 	: controller program that controls the servers      **
*****************************************************************************/

/* This program dynamically controls the number of servers that are servicing
the message queue - it takes as an input the server name and the number
of messages per server */

#include "uai.h"
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>

char serverName[256]; /* name of the process to fork out */
extern char processName[]; /* in library */
int  noOfMessagesPerServer; /* the number of messages to be handled by each */
int  messageTypeOfServer; /* the type that the server waits on */
int  serversRequired; /* number of servers needed */
int  noOfServersRunning = 0; /* number of servers running at the present instant */
int  debugFlag;
struct nmsgbuf *ptr;

/* function declaration */
void DEBUG(char *format,...);
int fork_or_kill_servers(int msqid);
int process_args(int argc, char **argv);

int main(int argc, char **argv)
{
  int msqid, n1, n2, clientID;
  nmsqid_ds *request;
  int noMessages;

 	process_args(argc, argv); 
/* find the server name and the no. of messages before forking out the new copy of server */
  	msqid = nmsgget(1001, 0666); /* create the connection to the message queue */

  	ptr = new nmsgbuf;

  	request = new nmsqid_ds;

	while(1) {
 	request->numberMsgsType = messageTypeOfServer;
	/* find out the number of messages of the type on the queue */

  	nmsgctl(msqid, IPC_STAT, request);
	noMessages = request -> numberMsgsType;
	/* this contains the number of messages  of a particular type */

        printf("got numberMsgsType = %d\n", request->numberMsgsType);
	serversRequired = noMessages/noOfMessagesPerServer ;  /* needed */
	DEBUG("servers required = %d, currently running = %d\n",
		serversRequired, noOfServersRunning);
	/* see how many servers are needed */
	fork_or_kill_servers(msqid);  
	sleep(10);
	}
}


int process_args(int argc, char **argv)
{
	/* processName is a global variable that it accesses */
	int  argCount;

	/* initialise the default parameters of the controller program */
	

	strcpy(processName,argv[0]); /* get process name */
	/* default values */
	strcpy(serverName,"sr");
	noOfMessagesPerServer = 2;
	messageTypeOfServer = 1;

	for (argc--, argv++; argc > 0; argc -= argCount, argv += argCount) {
        	argCount = 1;
        	if (!strcmp(*argv, "-s"))               
		{ /* extract the server name */
			strcpy(serverName, (*(argv+1)));
			argCount = 2;
		}
		if (!strcmp(*argv, "-n"))
		{ /* extract the number of messages per server */
			noOfMessagesPerServer = atoi(*(argv+1));	
			argCount = 2;
		}
		if (!strcmp(*argv, "-t"))
		{ /* extract the message type of the server */ 
			messageTypeOfServer = atoi(*(argv+1));
			argCount = 2;
		}			
		if(!strcmp(*argv, "-h"))
		{ /* help. Print the usage */
			printf("Network Based Message Queue Controller Program\n");
			printf("Usage : %s [-s <server name>] [-n <no of messages per server>] [-t <message type of server>] [-d (debugging)] [-h (for help)]\n", processName);
			exit(0);
		}
		if(!strcmp(*argv,"-d"))
		{ /*enable debugging option - echo all DEBUG messages */
			debugFlag = 1;
			DEBUG("Debugging messages enabled\n");
			argCount = 1;
		}
		
	}
}

int fork_or_kill_servers(int msqid)
{
char buf[256];
int i,count;
struct nmsgbuf *ptr;
	
	if(serversRequired > noOfServersRunning)
	{ /* fork so many servers */
		DEBUG("required  = %d, running = %d\n", serversRequired,
			noOfServersRunning);
		count = serversRequired - noOfServersRunning;
		for(i=0;i<count;i++)
		{ /* initiate some more servers */
			sprintf(buf,"%s &", serverName);
			system(buf);
			noOfServersRunning++; /* increment the count */
			DEBUG("con : starting another server - %s\n",serverName);
		}
	}
	
	/* send exit information to the servers in case too many are running */
	
	if(serversRequired < noOfServersRunning)
	{ /* send n messages of exit to the servers */

		ptr = new nmsgbuf;
		ptr -> mtype = messageTypeOfServer;
		ptr -> mtext[0] = -1; /* KILL MESSAGE */
		ptr -> mtext[1] = 0;

		count = noOfServersRunning - serversRequired;
		for(i=0;i<count;i++)
		{
			nmsgsnd(msqid,ptr,2,0); /* send 2 bytes over */
			DEBUG("con : sending kill message to server %s\n",
				serverName);
			noOfServersRunning --;
		}
		
	}
}

void DEBUG(char *format, ...)
{
    if (debugFlag) 
    {
        va_list ap;
        // You will get an unused variable message here -- ignore it.
        va_start(ap, format);
        vfprintf(stdout, format, ap);
        va_end(ap);
        fflush(stdout);
    }
}


