function EventCalendar () {
	this.events = [];
	this.eventById = {};
}

EventCalendar.DAYS_OF_THE_WEEK = [
	"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
	"Saturday"
];

EventCalendar.MONTHS_OF_THE_YEAR = [
	"January", "February", "March", "April", "May", "June",
	"July", "August", "September", "October", "November", "December"
];

EventCalendar.prototype.add = function (event) {
	this.events.push(event);
};

EventCalendar.prototype.finalize = function () {
	var i, event, group;

	var noonToday = new Date();
	noonToday.setHours(12);	// normalize to noon
	noonToday.setMinutes(0);	// for comparing by date only
	noonToday.setSeconds(0);
	noonToday.setMilliseconds(0);

	for (i = 0; i < this.events.length; ++i) {
		event = this.events[i];
		this.finalizeEvent(event);
		this.eventById[event.id] = event;
	}
	this.events.sort(function (a, b) {
		return a.startDate - b.startDate;
	});
	this.eventGroups = [];
	for (i = 0; i < this.events.length; ++i) {
		event = this.events[i];
		if (event.noonThatDay.getTime() < noonToday.getTime()) {
			continue;
		}
		if (!group || group.month !== event.month) {
			group = {
				month: event.month,
				events: []
			};
			this.eventGroups.push(group);
		}
		group.events.push(event);
	}
};

EventCalendar.prototype.finalizeEvent = function (event) {
	var yyyy, mm, dd, year, month, date;
	var startHour, startMinute, endHour, endMinute;

	event.id = "" + event.id; // coerce into string
	if (/^(\d\d\d\d)-(\d\d)-(\d\d)$/.test(event.date)) {
		yyyy  = RegExp.$1;
		mm    = RegExp.$2;
		dd    = RegExp.$3;
		year  = parseInt(yyyy, 10);
		month = parseInt(mm, 10) - 1; // need 0 to 11
		day   = parseInt(dd, 10);
	}
	if (/^(\d\d):(\d\d)$/.test(event.startTime)) {
		startHour   = RegExp.$1;
		startMinute = RegExp.$2;
		startHour   = parseInt(startHour, 10);
		startMinute = parseInt(startMinute, 10);
	}
	if (/^(\d\d):(\d\d)$/.test(event.endTime)) {
		endHour   = RegExp.$1;
		endMinute = RegExp.$2;
		endHour   = parseInt(endHour, 10);
		endMinute = parseInt(endMinute, 10);
	}
	event.noonThatDay = new Date(year, month, day, 
				     12, 0, 0, 0);
	event.startDate = new Date(year, month, day,
				   startHour, startMinute, 0, 0);
	event.endDate = new Date(year, month, day,
				 endHour, endMinute, 0, 0);
	event.month = this.formatMonth(event.startDate);
	event.formattedDate      = this.formatDate(event.startDate);
	event.formattedStartTime = this.formatTime(event.startDate);
	event.formattedEndTime   = this.formatTime(event.endDate);
	event.linkURL = "/for_the_trade/design_center/register.htm?id=" + 
		event.id;
	event.shortlyFormattedDate = mm + "/" + dd + "/" + yyyy;
};

// returns a string like "Wednesday, July 9, 2008".
EventCalendar.prototype.formatDate = function (date) {
	return EventCalendar.DAYS_OF_THE_WEEK[date.getDay()] +
		", " + EventCalendar.MONTHS_OF_THE_YEAR[date.getMonth()] +
		" " + date.getDate() + ", " + date.getFullYear();
};

// returns a string like "July 2008".
EventCalendar.prototype.formatMonth = function (date) {
	return EventCalendar.MONTHS_OF_THE_YEAR[date.getMonth()] +
		" " + date.getFullYear();
};

// returns a string like "Noon" or "Midnight" or "1:30 p.m.".
EventCalendar.prototype.formatTime = function (date) {
	var h, m, hh, mm, ap;

	h = date.getHours();
	m = date.getMinutes();
	if (h === 0 && m === 0) {
		return "Midnight";
	}
	if (h === 12 && m === 0) {
		return "Noon";
	}
	hh = ((h + 11) % 12 + 1).toString();
	mm = m.toString();
	while (mm.length < 2) {
		mm = "0" + mm;
	}
	ap = (h < 12) ? "a.m." : "p.m.";
	return hh + ":" + mm + " " + ap;
};

// returns a string like "2009 Calendar of Events" or
// "2009&ndash;2010 Calendar of Events".
EventCalendar.prototype.headingHTMLText = function () {
	var i, j, min_year, max_year, group, event;

	for (j = 0; j < this.eventGroups.length; ++j) {
		group = this.eventGroups[j];
		for (i = 0; i < group.events.length; ++i) {
			event = group.events[i];
			var start_year = event.startDate.getFullYear();
			var end_year   = event.endDate.getFullYear();
			if ((!min_year) || min_year > start_year) {
				min_year = start_year;
			}
			if ((!max_year) || max_year < end_year) {
				max_year = end_year;
			}
		}
	}

	if (min_year === max_year) {
		return min_year + " Calendar of Events";
	}
	else {
		return min_year + "&ndash;" + max_year + " Calendar of Events";
	}
};

EventCalendar.prototype.tableHTML = function () {
	var i, j, group, className, event;
	var html = "";

	for (j = 0; j < this.eventGroups.length; ++j) {
		group = this.eventGroups[j];
		html += "<h3 class='eventCalendarMonth'>" +
			group.month + "</h3>";
		html += "<table border='0' cellspacing='0' cellpadding='0' " + 
			"class='dataTableClosed eventCalendarTable'>";
		for (i = 0; i < group.events.length; ++i) {
			event = group.events[i];
			className = (i % 2) ? "even" : "odd";
			html += this.eventRowHTML(event, { 
				className: className,
				includeDescription: true,
				includeRegisterLink: true
			});
		}
		html += "</table>";
	}

	return html;
};

// for register.htm and register_thanks.htm
EventCalendar.prototype.singleEventTableHTML = function (event) {
	var html = "";

	html += "<table border='0' cellspacing='0' cellpadding='0' " + 
		"class='dataTableClosed eventCalendarTable singleEventTable'>";
	html += this.eventRowHTML(event, {});
	html += "</table>";

	return html;
};

EventCalendar.prototype.eventRowHTML = function (event, options) {
	var html = "";

	if (options.className) {
		html += "<tr class='" + options.className + "'>";
	}
	else {
		html += "<tr>";
	}
	html += "<td class='colA'>";
	html += "<h4 class='title'>" + event.title + "</h4>";
	if (options.includeDescription) {
		html += "<p class='eventDescription'>" +
			event.description + "</p>";
	}
	html += "</td>";
	html += "<td class='colB'>";
	html += "<p class='eventDate'>" + event.formattedDate + "<br />" + 
		event.formattedStartTime + " &ndash; " + 
		event.formattedEndTime + "</p>";
	html += "</td>";
	if (options.includeRegisterLink) {
		html += "<td class='colC'>";
		if (event.closed) {
			html += "<p class='eventLink'>";
			html += "This event is full.";
			html += "</p>";

			html += "<p class='eventLink fullline'>";
			html += "<a href='" + event.linkURL + "'>" +
				"Add name to Waitlist</a>";
			html += "</p>";
		}
		else {
			html += "<p class='eventLink'>";
			html += "<a href='" + event.linkURL + "'>" +
				"Register for this Event</a>";
			html += "</p>";

			html += "<p class='highlight fullline'>" +
				"Due to the prep work required " +
				"for events, registration will close 2 " + 
				"days before a scheduled event.</p>";
		}
		html += "</td>";
	}
	html += "</tr>";

	return html;
};

