#define BIRTHDAY_PATH "/CHANGE/THIS/PATH/birthday_data"
#define BIRTHDAY_PROGRAM_URL "/CHANGE/THIS/URL/wbw2"

#include <string.h>
#include <time.h>
#include <sys/types.h>

#include "cgic.h"

/* Month names to show the user */
char *months[12] =
{
  "january", "february", "march", "april", "may", "june",
  "july", "august", "september", "october", "november", "december"
};

/* Forward references */
void DayRequested();
void TodayRequested();
void AcceptSubmission();
void PresentOptions();
void OutputDay(int month, int day);
void BirthdayOutput (int day, int month, 
	char *name_s, char *url_s, char *email_s);
void BirthdayHead (char *request);
void BirthdayTail ();
void RemoveSpaces (char *dest, char *src);

int cgiMain ()
{
	cgiHeaderContentType("text/html");
	fprintf(cgiOut,
		"<HTML>\n<HEAD>\n");
	/* Look for requests for particular days
		and submissions of new entries. If
		the PATH_INFO indicates neither,
		display today's birthdays. In all
		three cases, present the user's
		next choices afterward. */

	if ((!strcmp(cgiPathInfo, "/day")) ||
		(!strcmp(cgiPathInfo, "day"))) {
		DayRequested();
	} else if ((!strcmp(cgiPathInfo, "/submit")) ||
		(!strcmp(cgiPathInfo, "submit"))) {
		AcceptSubmission();
	} else {
		TodayRequested();
	}
	PresentOptions();
	fprintf(cgiOut,
		"</BODY>\n</HTML>\n");
	return 0;
}

void TodayRequested()
{
	int month, day;
	struct tm *now_tm;
	time_t now_t;
	/* If we didn't find a request for a specific date,
		then output today's birthdays instead. */
	/* Retrieve the current time */
	time (&now_t);
	/* Break it down into month, day, year and so on */
	now_tm = gmtime (&now_t);
	month = now_tm->tm_mon;
	day = now_tm->tm_mday;
	/* Output today's birthdays */
	OutputDay(month, day);
}

void DayRequested()
{
	int month, day;

	/* The month will be one of the twelve possible strings, of course. */	
	cgiFormSelectSingle("month", months, 12, &month, 0);
	
	/* The day is an integer, so just use cgiFormIntegerBounded(). */
	cgiFormIntegerBounded("day", &day, 1, 31, 1);

	/* Output birthdays */
	OutputDay(month, day);
}

void AcceptSubmission()
{
	int month, day;
	char name[256];
	char url[256];
	char email[256];
	char path[256];
	FILE *out;

	/* Keep the results so we can complain if fields are missing. */
	int rMonth, rDay, rName, rEmail, rUrl;

	/* The month will be one of the twelve possible strings, of course. */	
	cgiFormSelectSingle("month", months, 12, &month, 0);
	
	/* The day is an integer, so just use cgiFormIntegerBounded(). */
	cgiFormIntegerBounded("day", &day, 1, 31, 1);

	/* Now the user's name, url and email address. */
	rName = cgiFormStringNoNewlines("name", name, sizeof(name));
	rUrl = cgiFormStringNoNewlines("url", url, sizeof(url));
	rEmail = cgiFormStringNoNewlines("email", email, sizeof(email));

	if ((rName == cgiFormNotFound) || 
		(rMonth == cgiFormNotFound) || (rDay == cgiFormNotFound))
	{
		/* Complain. */
		fprintf(cgiOut,
			"<title>Missing Fields</title></head>\n");
		fprintf(cgiOut,
			"<body>\n<h1>Missing Fields</h1>\n");
		fprintf(cgiOut,
			"Please fill out your name, your month of birth,\n");
		fprintf(cgiOut,
			"and your day of birth, at a minimum.\n");
		return;
	}

	/* All is well; add the data to the database. */
	sprintf(path, "%s/%d/%d", BIRTHDAY_PATH, month+1, day);
	out = fopen (path, "a");
	if (!out) {
		/* We can't access the data file to add to it. */
		fprintf(cgiOut,
			"<title>Can't Access Data File</title></head>\n");
		fprintf(cgiOut,
			"<body>\n<h1>Can't Access Data File</h1>\n");
		fprintf(cgiOut,
			"Please contact the administrator.\n");
		return;
	}
	fprintf(out, "%s\n%s\n%s\n", name, url, email);
	fclose(out);
	fprintf(cgiOut,
		"<title>WBW: Birthday added successfully.</title></head>\n");
	fprintf(cgiOut,
		"<body>\n<h1>WBW: Birthday added successfully.</h1>\n");
}

void OutputDay(int month, int day) {
	FILE *in;
	char path[256];
	int birthdayCount = 0;
	fprintf(cgiOut,
		"<title>WBW: birthdays for %d %s</title></head>\n",
		day, months[month]);
	fprintf(cgiOut,
		"<body>\n<h1>WBW: birthdays for %d %s</h1>\n",
		day, months[month]);
	sprintf(path, "%s/%d/%d", BIRTHDAY_PATH, month+1, day);
	in = fopen (path, "r");
	if (in) {
		while (!feof (in)) {
			char name_s[512], url_s[512], email_s[512];
			char nameS[512], urlS[512], emailS[512];
			if (!fgets (name_s, 512, in)) {
				break;
			}
			RemoveSpaces (nameS, name_s);
			if (!fgets (url_s, 512, in)) {
				break;
			}
			RemoveSpaces (urlS, url_s);
			if (!fgets (email_s, 512, in)) {
				break;
			}
			RemoveSpaces (emailS, email_s);
			if (!birthdayCount) {
				char s[81];
				sprintf(s, "%d %s", 
					day, months[month]);
				BirthdayHead (s);
			}
			birthdayCount++;
			BirthdayOutput (day, month,
				nameS, urlS, emailS);
		}
	}
	fclose (in);
	if (birthdayCount) {
		BirthdayTail ();
	} else {
		fprintf(cgiOut,
		"<em>No birthdays have been entered for this day.</em>\n");
	}
}

void BirthdayOutput (int day, int month,
		char *name_s, char *url_s, char *email_s) 
{
	fprintf(cgiOut, "<LI>");
	if (strlen (url_s)) {
		fprintf(cgiOut,
			"<A HREF=\"%s\">", url_s);
	}
	fprintf(cgiOut, "%d %s: ", day, months[month]);
	fprintf(cgiOut, "<STRONG>%s</STRONG>", name_s);
	if (strlen (email_s)) {
		fprintf(cgiOut, " <EM>%s</EM>\n", email_s);
	}
	if (strlen (url_s)) {
		fprintf(cgiOut, "</A>\n");
	}
	fprintf(cgiOut, "</LI>\n");
}

void BirthdayHead (char *request) 
{
	fprintf(cgiOut, "<H2>Birthdays for: %s</H2><UL>\n", request);
}

void BirthdayTail () 
{
	fprintf(cgiOut, "</UL>\n");
	fprintf(cgiOut, "<P><em>Remember, the Birthday Server ");
	fprintf(cgiOut, "runs on Greenwich Mean Time.</em>\n");
}

void PresentOptions()
{
	int i;
	fprintf(cgiOut, "<p>\n");
	fprintf(cgiOut, "<hr>\n");
	fprintf(cgiOut, "<h2>Global Birthday Navigator (GBN)</h2>\n");

	/* Make sure that PATH_INFO will distinguish this form from others */
	fprintf(cgiOut, "<form action=\"%s/day\" method=\"POST\">\n", 
		BIRTHDAY_PROGRAM_URL);

	fprintf(cgiOut, "Month: \n");
	fprintf(cgiOut, "<select name=\"month\">\n");
	for (i=0; (i < 12); i++) {
		fprintf(cgiOut, "<option>%s\n", months[i]);
	}
	fprintf(cgiOut, "</select>\n");

	fprintf(cgiOut, 
		"Day: <input size=\"3\" type=\"text\" name=\"day\"> \n");

	fprintf(cgiOut, "<input type=\"submit\"> <input type=\"reset\">\n");
	fprintf(cgiOut, "</form>\n");
	fprintf(cgiOut, "<hr>\n");
	fprintf(cgiOut, "<h2>Universal Birthday Form (UBF)</h2>\n");

	/* Make sure that PATH_INFO will distinguish this form from others */
	fprintf(cgiOut, "<form action=\"%s/submit\" method=\"POST\">\n", 
		BIRTHDAY_PROGRAM_URL);

	fprintf(cgiOut, "Month: \n");
	fprintf(cgiOut, "<select name=\"month\">\n");
	for (i=0; (i < 12); i++) {
		fprintf(cgiOut, "<option>%s\n", months[i]);
	}
	fprintf(cgiOut, "</select>\n\n");

	fprintf(cgiOut, 
		"Day: <input size=\"3\" type=\"text\" name=\"day\"><p>\n");

	fprintf(cgiOut, "Name: <input type=\"text\" name=\"name\"><p>\n");
	fprintf(cgiOut, "URL: <input type=\"text\" name=\"url\"><p>\n");
	fprintf(cgiOut, "Email: <input type=\"text\" name=\"email\"><p>\n");
	fprintf(cgiOut, "<input type=\"submit\" value=\"Submit Birthday\"> \n");
	fprintf(cgiOut, "<input type=\"reset\">\n");

	fprintf(cgiOut, "</form>\n");
}

void RemoveSpaces(char *dest, char *src) {
	/* Remove all leading and trailing spaces. */
	char *last;

	/* First, skip to the first non-space character 
		in the source string. */
	while (*src) {
		if (!isspace(*src)) {
			break;
		}
		src++;
	}	

	/* Now, copy the source string to the destination string. */
	strcpy(dest, src);

	/* Now, find the last non-space character in the destination string;
		move downward through the string from the end. */
	if (!strlen(dest)) {
		return;
	}	
	last = dest + strlen(dest) - 1;	
	while (last != dest) {
		if (!isspace(*last)) {
			/* We have found the last non-space character
				in the string, so place a final null
				immediately after it. */
			*(last + 1) = '\0';
			break;
		}
		last--;
	}		
}
