/**Chris Jarrett
 * Comp289 - Lab7
 * Usage: msgLogger <log file>
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/neutrino.h>
#include <string.h>
#include "msg.h"
#include <process.h>

//global for the log file pointer
FILE *logFile;

int processMessage(int rcvid, MESSAGE_CLIENT *m, char *result);
void handleSignal();
int processPulse(MESSAGE *msg, char *result);
void setupSignalAndTimer();

int main(int argc, char *argv[]) {
	const int SSIZE = 512;
	int chid;
	int clientID;
	MESSAGE *msg = malloc(sizeof(MESSAGE));
	FILE *pidFile;
	int status = 0;
	MESSAGE_CLIENT *client = malloc(sizeof(MESSAGE_CLIENT));
	char msgString[SSIZE];

	//not the right number of args
	if(argc != 2) {
		printf("Incorrect arguments. Should be: \"%s <log name>\".", argv[0]);
		return EXIT_FAILURE;
	}

	//get pid file to make from input
	char *loggerPidName;
	loggerPidName = malloc(strlen(argv[0]) + 5);
	strcpy(loggerPidName, argv[0]);
	strcat(loggerPidName, ".pid");

	//create channel and write the pid file
	pidFile = fopen(loggerPidName, "w+");
	chid = ChannelCreate(0);
	fprintf(pidFile, "0 %d %d\n", getpid(), chid);
	fclose(pidFile);

	//open the log file to append
	logFile = fopen(argv[1], "a+");

	//set the signal and handler
	signal(SIGUSR2, handleSignal);
	setupSignalAndTimer();

	while(1) {
		//receive message
		clientID = MsgReceive(chid, msg, sizeof(MESSAGE), NULL);

		//if it's a pulse
		if(clientID == 0) {
			processPulse(msg, msgString);
		//if it's a message
		} else {
			//get the message and process
			client = &msg->client;
			status = processMessage(clientID, client, msgString);

			//reply
			MsgReply(clientID, status, NULL, 0);
		}


		//write to the lof gile
		fprintf(logFile, "%s", msgString);

		//if it's the end mssage, cleanup and exit
		if(status == MSG_END) {
			remove(loggerPidName);
			free(loggerPidName);
			fclose(logFile);
			return EXIT_SUCCESS;
		}
	}
}
/**
 * function pointer used to handle signals
 */
void handleSignal() {\
	//get the time
	time_t theTime = time(NULL);
	char timeString[26];
	ctime_r(&theTime, timeString);
	timeString[24] = ':';

	//write the time and a message saying a pulse was received (may or may not be wanted, can easily be removed)
	fprintf(logFile, "Received a SIGUSR2 signal at: %s\n", timeString);
	//flush the buffer for the log file to disk
	fflush(logFile);
}

/**
 * function to handle messages
 */
int processMessage(int rcvid, MESSAGE_CLIENT *m, char *result) {
	struct _msg_info* info = malloc(sizeof(struct _msg_info));

	//get the time
	time_t theTime = time(NULL);
	char timeString[26];
	ctime_r(&theTime, timeString);
	timeString[24] = ':';

	switch(m->m_hdr) {
		case MSG_DATA:
			//get the message info
			MsgInfo(rcvid, info);

			//put the strings needed in the pointer to be written
			sprintf (result, "%s %d/%d/%d sent: %s\n", timeString, info->nd, info->pid, info->chid, m->m_data);

			//cleanup and return
			free(info);
			return MSG_OK;

		case MSG_END:
			//put the strings needed in the pointer to be written
			sprintf(result, "%s Shutdown message received\n", timeString);

			//cleanup and return
			free(info);
			return MSG_END;

		default:
			//get the message info
			MsgInfo(rcvid, info);

			//put the strings needed in the pointer to be written
			sprintf (result, "%s %d/%d/%d received invalid data\n", timeString, info->nd, info->pid, info->chid);

			//cleanup and return
			free(info);
			return MSG_INVALID;
	}
}
/**
 * function to handle pulses
 */
int processPulse(MESSAGE *msg, char *result) {
	//get the time
	time_t theTime = time(NULL);
	char timeString[26];
	ctime_r(&theTime, timeString);
	timeString[24] = ':';

	//put the strings needed in the pointer to be written
	sprintf(result, "%s received a pulse with code: %d\n", timeString, msg->pulse.code);
	return 1;
}

/**
 * function to make and initialize the signal timer
 */
void setupSignalAndTimer() {
	timer_t timerid; // timer ID for timer
	struct sigevent event; // event to deliver
	struct itimerspec timer; // the timer data struct


	// set up the event that we want to deliver -- a pulse
	SIGEV_SIGNAL_INIT (&event, SIGUSR2);
	// create the timer, binding it to the event
	if(timer_create(CLOCK_REALTIME, &event, &timerid) == -1) {
		fprintf (stderr, "couldn't create a timer");
		perror (NULL);
		exit (EXIT_FAILURE);
	}
	// setup the timer (1s delay, 1s reload)
	timer.it_value.tv_sec = 2;
	timer.it_value.tv_nsec = 0;
	timer.it_interval.tv_sec = 7;
	timer.it_interval.tv_nsec = 0;
	// and start it!
	timer_settime (timerid, 0, &timer, NULL);
}

