//
// Enhanced JavaScript Event Calendar
//
// Author:  Joe Ball
// Website: http://www.joeball.com
// Email: joeball@joeball.com
// Version 0.4 - (15-Dec-2005)
//
// based on an earlier script by Kevin Ilsen (http://calendar.ilsen.net or kevin@ilsen.net)
// based on an earlier script by Rick Pike (http://calendar.pikesys.com or calendar@pikesys.com)

// Configurable values are set to defaults here; you can override them before calling Calendar( ) from your HTML page
var altAPrevDown = ""//new Image(); // allow a user entered a link like an image 
var altAPrevUp = ""//new Image();// allow a user entered a link like an image 
var altANextDown = ""//new Image();
var altANextUp = ""//new Image();

//altAPrevUp.src = "/images/prevup.gif"; // allow a user entered a link like an image 
//altANextUp.src = "/images/nextup.gif";
//altAPrevDown.src = "/images/prevdwn.gif"; // allow a user entered a link like an image 
//altANextDown.src = "/images/nextdwn.gif";

var popUpX = 0; // used for a pop up window
var popUpY = 0;
var popUpW = 50;
var popUpH = 50;
var popUpTitle = "Calender Event";
var divHeight = 100;
var makeScrollable = false;

function prevDown() {
if (document.images) document.prev.src = altAPrevDown.src;
}
function nextDown() {
if (document.images) document.next.src = altANextDown.src;
}

function popUp(dte,item)	{
//alert(Events[dte][item].link);
	//alert(document.getElementById("calevent").innerHTML);
	//document.getElementById("calevent").innerHTML = Events[dte][item].alt;
	document.getElementById("calevent").innerHTML = Events[dte][item].alt;

}

// Configurable values are set to defaults here; you can override them before calling Calendar( ) from your HTML page

var SpecialDay=1;	// 1=Sunday, 2=Monday, . . . 7=Saturday
var ColorBackground="ffcc00";
var ColorSpecialDay = "red";
var ColorToday = "green";
var ColorEvent = "blue";
var showAltDate = false;  	// add display of alternate date using results from user supplied "getAltMonth(dy, mo, yr, last)" and "getAltDate(dy, mo, yr)" functions
var showHolidays = false; 	// add display of holidays using result from user supplied "holidays(dy, mo, yr)" function
var showAltHoly = false; 	// add display of alternate holidays using result from user supplied "getAltHoly(dy, mo, yr)" function
var showMsgBox = false; 	// span empty cells (before 1st day and after last) for messageBox use
var showMini =false; 		// add minimonth display of prior and next months if first and/or last boxes are available 
var showTopNav = true; 		// enable month navigation (might disable for print version)
var showBottomNav = false; 		// enable month navigation (might disable for print version)
var showImages = false; 	// enable event images (might disable for print version)
var showLinks = true; 		// enable event hyperlinks (might disable for print version)
var msgBoxColor = "#ffcc99";
var navColor = "#ff9559";
var imageAlign = "left"; 	// default event image alignment
var imageScale = 100;		// percent scale factor for images
var altAlign = true; 		// alternate left/right alignment of event images on same date for readability
var DefaultFormat = "custom"; // for compatibility; set to "layer" to simplify formatting
var ExportPage = ""; 		// name of html page for displaying event text for export
var PrintPage = ""; 		// name of html page for printer-friendly format

// all format codes must have "|" to separate before and after tags
var DateFontSize=3;
var AltDateFormat = "<font color=#000000 size=2>|</font>";
var MonthFormat = "<font size=" + DateFontSize + "><b>|</b></font>";
var AltMonthFormat = "<br><font color=#000000 size=" + DateFontSize/2 + ">|</font>";
var HolidayFormat = "<font color=#000000 size=2><b><center>|</center></b></font>";
var AltHolyFormat = "<font  size=2><b><center>|</center></b></font>";
var DefaultLayerFormat = "<font size=2>|</font>";
var defaultMsgBox = "Note: The information here may not be current; please confirm dates and times.<p>";

// Initialize the range of the calendar to Jan - Dec of the current year.
// Event definitions will change this as needed; or it can be explicitly
// overridden before calling Calendar( ) from the HTML page.

var today = new Date();
var FirstMonth=GetFullYear(today) * 100 +1;
var LastMonth=FirstMonth + 11;

// Layers[] is an array of layer names and default formats. Call DefineLayer( ) to add the
// layer name and corresponding format. New layer names in event definitions will
// be added automatically (watch case and spelling).

var Layers = new Array;
var LayerString = "|";
var layerCount = 0;
var layerChange = false;

// MsgBoxes[] is a SPARSE array; Call AddMsgBox( ) to populate it

var MsgBoxes = new Array;

// Events[] is a SPARSE array; Call AddEvent( ) to populate it or DefineEvent( ) for
// compatibility with existing calendar definition scripts.

var Events = new Array;
// SpecialDay=1;		// 0=none, 1=Sunday, 2=Monday, . . . 7=Saturday
// ColorBackground="ffffcc";
// ColorSpecialDay = "red";
// ColorToday = "green";
// ColorEvent = "blue";
// var showAltDate = false;  	// add display of alternate date using results from user supplied "getAltMonth(dy, mo, yr, last)" and "getAltDate(dy, mo, yr)" functions
// showHolidays = false; 	// add display of holidays using result from user supplied "holidays(dy, mo, yr)" function
// showAltHoly = false; 		// add display of alternate holidays using result from user supplied "getAltHoly(dy, mo, yr)" function
// showMsgBox = true; 		// span empty cells (before 1st day and after last) for messageBox use
// showMini = true; 		// add minimonth display of prior and next months if first and/or last boxes are available 
// showNav = true; 		// enable month navigation (might disable for print version)
// showImages = true; 		// enable event images (might disable for print version)
// showLinks = true; 		// enable event hyperlinks (might disable for print version)
// msgBoxColor = "#ffcc99";
// navColor = "#ffff99";
// imageAlign = "left"; 		// default event image alignment
// imageScale = 100;		// percent scale factor for images
// altAlign = true; 		// alternate left/right alignment of event images on same date for readability
// DefaultFormat = "custom"; 	// for compatibility; set to "layer" to simplify formatting
// ExportPage = ""; 		// name of html page for displaying event text for export
// PrintPage = ""; 		// name of html page for printer-friendly format

// all format codes must have "|" to separate before and after tags
// DateFontSize=5;
// AltDateFormat = "<font color=#999999 size=2>|</font>";
// MonthFormat = "<font size=" + DateFontSize + "><b>|</b></font>";
// AltMonthFormat = "<br><font color=#999999 size=" + DateFontSize/2 + ">|</font>";
// HolidayFormat = "<font color=#999999 size=2><b><center>|</center></b></font>";
// AltHolyFormat = "<font  size=2><b><center>|</center></b></font>";
// LayerFormat = "<font size=2>|</font>";

// msgBox message (it will only be shown IF it finds enough space)
//defaultMsgBox = "Note: The information here may not be current; please confirm dates and times.<p>";

// map alternate date and holiday functions to user supplied functions here
altDateStyle = 2;
altMonthStyle = 1;
//function getAltMonth(first, month, year, last) {
//	var tmp = my_date(first, month, year, altMonthStyle) + " - " + my_date(last, month, year, altMonthStyle);
//	return tmp;
//}
//function getAltDate(day, month, year) { return my_date(day, month, year, altDateStyle); }
function holidays(day, month, year) { return my_holiday(day, month, year); }
//function getAltHoly(day, month, year) { return my_alt_holiday(day, month, year); }


// Each event is defined by calling the AddEvent( ) routine with the following parameters:
//
//   AddEvent(Date, Description, Layer, Format, Link, Image, Width, Height, Align, Alt)
//        Date is a numeric value in the format YYYYMMDD
//        Description is a string (may include embedded HTML tags such as <BR>, <strong>, etc.)
//        Layer is an event category whose display on the calendar can be toggled on/off by the user
//        Format specifies the source of the format info for Description. Note that any embedded
//        formats in Description will still be applied; this argument is primarily to provide
//        a more convenient way to specify formats. 
//            "layer" = use default format from layer definition (plus any embedded tags!)
//            "custom" = only use format tags embedded in Description string
//            "<...>|</...>" = series of before and after tags separated by a "|" to wrap around
//               Description (plus any embedded tags!)  
//        Link is the URL of the target page if a hyperlink is desired from this event entry
//        Image is the URL of the image if you want to display an image with this event
//        Width is the width of the image in pixels
//        Height is the height of the image in pixels
//        Align is the alignment of the image such as "left", or "right"
//        Alt is the alternate text of the image (for mouseover or non-graphic browser)

// The function DefineEvent(Date, Description, Link, Image, Width, Height) is used
// for compatibility with previous calendar definition scripts

// Event constructor
function Event(description, layer, format, link, image, width, height, align, alt) {

	this.description = description;

	if (link) this.link = link;
   	if (alt) this.alt = alt;
	if (image) {
	   this.image = image;
	   if (width) this.width = width;
	   if (height) this.height = height;
	   if (align) this.align = align;
	   //alert("Event: ("+this.width+","+this.height+")");
	}
	this.layer = (layer ? layer : "default");	 	// must have some associated layer
	
	if (format) {
	   if (CheckFormat(format)) this.format = format;
	}
}

// Compatibility function for existing calendar definition scripts
function DefineEvent(Date, Description, Link, Image, Width, Height) {
	AddEvent(Date, Description, "", "", Link, Image, Width, Height, "", "");
}

function AddEvent(Date, Description, Layer, Format, Link, Image, Width, Height, Align, Alt) {
	var i;

	if (!Events[Date]) Events[Date] = new Array;
	i = Events[Date].length;
	if (Link == "popUp") 
	  Link = "javascript:popUp("+Date+","+i+");showMe()";
//alert(Alt);
	Events[Date][i] = new Event(Description, Layer, Format, Link, Image, Width, Height, Align, Alt);

	// Adjust the minimum and maximum month & year to include this date
	tmp = Math.floor(Date / 100);
	if (tmp < FirstMonth) FirstMonth = tmp;
	if (tmp > LastMonth) LastMonth = tmp;

	// if EventLayer not in Layers, add it
	// NOTE: watch case in DefineLayer and DefineEvent to avoid undesired "duplicates"

	//alert("AddEvent("+Date+","+Description+","+Width+","+Height+"...)");
	if (Layer && !Layers[Layer]) DefineLayer(Layer);
}

// Layer constructor
function Layer(format, show) {
	if (format) {	
	   if (format.indexOf("|")>0) {
	      this.format = format;
	   } else {
	      alert("Invalid Calendar Format String: " + format);
	   }
	} else {
	   this.format = DefaultLayerFormat;
	}
	this.show = (show=="false" ? "false" : "true");	// watch boolean vs. string arg
}

function DefineLayer(LayerName, LayerFormat, LayerShow) {
	Layers[LayerName] = new Layer(LayerFormat, LayerShow);
	layerCount++;
}

// Utility function to populate an array with values
function arr() {
	for (var n=0;n<arr.arguments.length;n++) {
		this[n+1] = arr.arguments[n];
	}
}

// Create the array of month names (used in various places)
var months = new arr("January","February","March","April","May","June","July","August","September","October","November","December");

// Calendar(obj) is the only routine that needs to be called to display the calendar
var cookieName = "layerCalendar";
var pre, post, tmp, gloMo, gloYr, gloYearmonth;

function Calendar() {
	var curdy, curmo, yr, mo, dy, firstday, yearmonth, bgn, lastdate, jump;
	var weekdays = new arr("Sun","Mon","Tue","Wed","Thu","Fri","Sat");
	var thispage = window.document.location.pathname;
	//alert(thispage);
	var myMsgBox = "Put this FREE calendar script on your own site; see <a href=http://calendar.pikesys.com>calendar.pikesys.com</a>.<p>";

	// define default MsgBox messages
	//AddMsgBox(0, defaultMsgBox);
	//AddMsgBox(0, myMsgBox);
	
	// Save current day and month for comparison
	curdy = today.getDate();
	curmo = today.getMonth()+1;
	
	initCal(curmo);
	mo = gloMo; yr = gloYr; yearmonth = gloYearmonth;
	getLayersVisible(); 		// get layer visibility settings from cookie
	//alert(yearmonth);
	// Create a date object for the first day of the desired month
	bgn = new Date(months[mo] + " 1," + yr);
	// Get the day-of-week of the first day, and the # days in the month
	firstday = bgn.getDay();
	lastdate = NumDaysIn(mo,yr);
	lastday = 1+(firstday + lastdate - 1)%7;
	prev = next = "";
	if (showTopNav) {
		if (yearmonth > FirstMonth)
/*			if (altAPrevUp.src != "") {
				alert(altAPrevUp.src);
				prev = '<a style="color:#ff9559;" target="_self" href="' 
				+ thispage + '?'+PrevYearMonth(yearmonth)+
				'"><img name=prev onMousedown="prevDown()" width=60 border=0 height=30 src='+altAPrevUp.src+'></a>';
			}
			else { */
				prev = '<a  target="_self" style="text-decoration:none;" href="' + thispage + '?'+PrevYearMonth(yearmonth)+'">';
		//}
		if (yearmonth < LastMonth)
		/*	if (altANextUp.src != "") {
				next = '<a style="color:#ff9559;text-decoration: none;" target="_self" href="' + 
				thispage + '?'+NextYearMonth(yearmonth)+
				'"><img name=next onMousedown="nextDown()" border=0 width=60 height=30 src="'+altANextUp.src+'"></a>';
			}
			else { */
				next = '<a target="_self" style="text-decoration:none;" href="' + thispage + '?'+NextYearMonth(yearmonth)+'">';
			//}
	}

	parseFormat(MonthFormat);
	tmp = "<TABLE BORDER=2 ID=cal WIDTH=600 BGCOLOR="+ColorBackground+"><TR BORDER=0 BGCOLOR="+navColor+">";
	tmp += "<TD ALIGN=left valign=top colspan=2 BGCOLOR="+navColor+" style=\"padding-left:12px;padding-top:10px;\" height=125>" + prev;
	document.write(tmp);
	MiniMonth(PrevYearMonth(yearmonth));
	tmp = (prev=="" ? "" : prev) + "</a>";
	tmp += "</TD><TD ALIGN=CENTER COLSPAN=3><BR>" + BuildSelectionList(yearmonth, thispage) +"<a href='report.cfm?events="+yearmonth+"' target='_blank'>View current month event list</a>"; //+ pre + months[mo] + " " + yr + post;
 
	
//	if (showAltDate) {
//		parseFormat(AltMonthFormat);
//		altMonth = getAltMonth(1, mo, yr, lastdate);
//		tmp += pre + (altMonth ? altMonth : "") + post;
//	}
	tmp += "</TD><TD ALIGN=left valign=top colspan=2 BGCOLOR="+navColor+" style=\"padding-left:12px;padding-top:10px;\"height=125>";
	tmp += next;
	document.write(tmp);
	MiniMonth(NextYearMonth(yearmonth));
	document.write((next=="" ? "" : "</a>") + "</TD></TR>");
	//document.write(tmp);
	document.write("<TR BGCOLOR="+navColor+">");
	
	for (var i=1;i<=7;i++){
		document.write("<TD ALIGN=CENTER WIDTH=14%><FONT SIZE=2>"+weekdays[i]+"</FONT></TD>");
	}
	dy = 1;
	document.write("</TR><TR>");
 //alert(dy+" "+lastdate);
	while (dy <= lastdate) {
		for (var i=1; i<=7; i++) {
			
			// If the day cell is before the first day of the month, print a miniMonth display of previous month in the first cell, 
			// otherwise print a space in this cell of the table.
			if (dy == 1 && i <= firstday) {
				if (i == 1) {
					if (showMini) {
						document.write("<TD height=85 BGCOLOR="+ColorBackground+">");	
						MiniMonth(PrevYearMonth(yearmonth));
					} else {
						document.write("<TD height=85>&nbsp;");
					}
				} else if (showMsgBox && i==2) { 	// span empty cells to allow messageBox
					msgSpan = firstday - 1;
					document.write("<TD height=85 BGCOLOR=" + navColor + " COLSPAN=" + msgSpan +">&nbsp;");
					DoMsgBox(yearmonth, msgSpan);
				} else if (!showMsgBox) {
					document.write("<TD height=85>&nbsp;");
				}
				document.write("</TD>");

			// If the day cell is after the last day of the month, print a miniMonth display of following month in the last cell, 
			// otherwise print a space in this cell of the table.
			} else if (dy > lastdate) {
				if (i == 7) {
					if (showMini) {
						document.write("<TD height=85 BGCOLOR="+ColorBackground+">");	
						MiniMonth(NextYearMonth(yearmonth));
					} else {
						document.write("<TD height=85>&nbsp;");
					}
				} else if (showMsgBox && i==(lastday+1)) { 	// span empty cells to allow messageBox
					msgSpan = 6 - lastday;
					document.write("<TD height=85 BGCOLOR=" + navColor + " COLSPAN=" + msgSpan +">&nbsp;");
					DoMsgBox(yearmonth, msgSpan);
				} else if (!showMsgBox) {
					document.write("<TD height=85>&nbsp;");
				}
				document.write("</TD>");

			// Otherwise, write date and the event, if any, in this cell of the table.
			} else { 
				document.write("<TD height=85 VALIGN=TOP>");
				ShowDate(yr,mo,dy,i,curmo,curdy);
				document.write("</TD>");				
				dy++;
			}
		}
		document.write("</TR>");
	}
/*	if (showBottomNav) {
		prev = next = "&nbsp;";
		if (yearmonth > FirstMonth)
			if (altAPrevUp.src != "") {
				prev = '<a target="_self" href="' + thispage + '?'+PrevYearMonth(yearmonth)+
				'" onMouseDown="prevDown()"><img width=60 height=30 src='+altAPrevUp.src+'></a>';
			}
			else {
				prev = '<a target="_self" href="' + thispage + '?'+PrevYearMonth(yearmonth)+'">&lt;-- View '+
				months[PrevMonth(mo)]+'</a>';
			}
		if (yearmonth < LastMonth)
			if (altANextUp.src != "") {
				next = '<a target="_self" href="' + thispage + '?'+NextYearMonth(yearmonth)+
				'" onMouseDown="nextDown()"><img width=60 height=30 src="'+altANextUp.src+'"></a>';
			}
			else {
				next = '<a target="_self" href="' + thispage + '?'+NextYearMonth(yearmonth)+'">View '+
				months[NextMonth(mo)]+' --&gt;</a>';
			}
			tmp = "<TR BGCOLOR="+navColor+"><TD ALIGN=CENTER BGCOLOR="+navColor+">" + prev + "</TD>";
			tmp += "<TD colspan=5 align=center valign=middle><div align=\"center\" id=\"popdiv\" name=\"popdiv\"></div>";
			document.write(tmp);
			tmp = "</TD><TD ALIGN=CENTER BGCOLOR="+navColor+">" + next + "</TD>";
			document.write(tmp + "</TR>");
		}
	else {
		tmp = "<TR BGCOLOR="+navColor+"><TD Height="+divHeight+" ALIGN=CENTER BGCOLOR="+navColor;
		tmp += " colspan=2>";
		tmp += "<table border=0 id=tablea width='100%'><tr><td>";
		document.write(tmp);
		tmp = "";
		MiniMonth(PrevYearMonth(yearmonth));
		tmp = "</td></tr></table></TD><td colspan=3 width=240>&nbsp;</td>";
		tmp += "<TD Height="+divHeight+" ALIGN=CENTER BGCOLOR="+navColor;
		tmp += " colspan=2><table border=0 id=tablea width='100%'><tr><td>";
		document.write(tmp);
		MiniMonth(NextYearMonth(yearmonth));
		document.write("</td></tr></table></td></TR>");
	}
*/
	document.write("</TABLE>");
//	if (makeScrollable) 
	//	makeScrollableTable('tablea',false,'125');
}

// Display a date in the appropriate color, with events (if there are any)

function ShowDate(yr, mo, dy, dayofweek, currentmonth, currentday) {

	var ind, DayHighlighted, tmp, event;

	tmp = "<TABLE><TR VALIGN=TOP><TD ALIGN=LEFT WIDTH=10%>";
	tmp += "<FONT SIZE=" + DateFontSize;	// Note open tag!	
	DayHighlighted = false;

	if ((mo == currentmonth) && (dy == currentday)) {
		tmp += " COLOR=" + ColorToday;
		DayHighlighted = true;
	} else if (dayofweek == SpecialDay) {
		tmp += " COLOR=" + ColorSpecialDay;
		DayHighlighted = true;
	}

	ind = (((yr * 100) + mo) * 100) + dy;
	if (Events[ind]) {
		//event = Events[ind];
		if (!DayHighlighted) tmp += " COLOR=" + ColorEvent;
//	} else {
//		event = "&nbsp;<BR>&nbsp;";
	}
	
	tmp += "><B>" + dy + (dy<10 ? "&nbsp;" : "") + "&nbsp;</B></FONT></TD>";	 	// close tag
	document.write(tmp);
	
	if (showAltDate) {
		altDate = getAltDate(dy, mo, yr);
		parseFormat(AltDateFormat);
		document.write("<TD ALIGN=RIGHT>" + pre + altDate + post + "</TD>");
	}
	document.write("</TR></TABLE>");

	if (showAltHoly) {
		tmp = getAltHoly(dy,mo,yr);
		if (tmp) {
			parseFormat(AltHolyFormat);
			document.write(pre + tmp + post + "<BR>");
		}
	}
	
	if (showHolidays) {
		tmp = holidays(dy,mo,yr);
		if (tmp) {
			parseFormat(HolidayFormat);
			document.write(pre + tmp + post + "<BR>");
		}
	}
//	document.write("<P><FONT SIZE=1>" + event + "</FONT>");

	images=0;
	for (j in Events[ind]) {
		ev = Events[ind][j];
		// with(Events[ind][j]) { // greatly improves readability of following
		//for (k in ev) { alert("ev["+k+"]="+ev[k]) }
		//  document.write("Events[" + ind + "][" + j + "][" + k + "] = " + EscapeLtGt(Events[ind][j][k]), "<br>");
		//alert("-> Layers[Events["+ind+"]["+j+"]."+ev.layer+"].show="+Layers[ev.layer].show);
		tmp = "";		
		if (Layers[ev.layer].show == "true") {
			//alert("(+)showing event for "+ind+" in layer "+ev.layer);
			// Build the HTML string for this event
			tmp += (j>0 ? "<br>" : "");
			if (ev.image && showImages) {
				if (ev.align) {
					align = ev.align;
				} else if (altAlign && images>0) {
					align = (lastAlign=="left" ? "right" : "left");
				} else {
					align = imageAlign;
				}
				tmp += '<img src="' + ev.image + 
					   (ev.width ? '"  width="' + ev.width*imageScale/100 : '') +
					   (ev.height ? '" height="' + ev.height*imageScale/100 : '') +
					   (ev.alt ? '" alt="' + ev.alt : '') +					   
					   '" align="' + align + '" valign="top">';
				lastAlign = align;
				images++;
			}
			format = "";
			if (ev.format == "layer") { // use format from layer (and embedded tags)
				format = Layers[ev.layer].format;
			} else if (ev.format == "custom") { // use only embedded tags
				format = "";
			} else if (ev.format) { 	// format string?
				if (CheckFormat(ev.format)) format = ev.format;
			} else if (DefaultFormat == "layer") { // use format from layer if no custom format
				format = Layers[ev.layer].format;
			}
			parseFormat(format);
			//tmp += pre + (ev.link && showLinks ? ev.description.link(ev.link) : ev.description) + post + "<br>";
			tmp += pre + (ev.link && showLinks ? "<a class=\"eventlink\" href="+ev.link+">"+ev.description+"</a>" : ev.description) + post + "<br>";
			
		} else {
			//alert("(-)skipping event for "+ind+" in layer "+ev.layer);
		}
	document.write("<FONT SIZE=1>" + tmp + "</FONT>");
	}
}

function exportCal( ) {
	var curdy, curmo, yr, mo, dy, firstday, yearmonth, lastdate;

	// Save current day and month for comparison
	curdy = today.getDate();
	curmo = today.getMonth()+1;

	initCal(curmo);
	mo = gloMo; yr = gloYr; yearmonth = gloYearmonth;
	getLayersVisible();	
	
	// Create a date object for the first day of the desired month
	lastdate = NumDaysIn(mo,yr);

	tmp = "<textarea NAME=\"txt\"  ROWS=20 COLS=75 WRAP=VIRTUAL>";
	tmp += '"Subject","Start Date","Start Time","End Date","End Time","All day event","Description","Show time as","Location"\n';
	document.write(tmp);
	for (dy=1; dy<=lastdate; dy++) {
		ind = (((yr * 100) + mo) * 100) + dy;
		evdate = mo + "/" + dy + "/" + yr;
		for (j in Events[ind]) {
			ev = Events[ind][j];
			if (Layers[ev.layer].show == "true") {
				//alert("(+)showing event for "+ind+" in layer "+ev.layer);
				tmp = qw(ev.description) + "," + qw(evdate) + ",,,," + qw("true") + ",," + 
					 qw("3") + "," + qw("CalendarScript");
				if (ev.description) document.write(tmp+"\n");
			} else {
				//alert("(-)skipping event for "+ind+" in layer "+ev.layer);
			}
		}
	}
	document.write("</textarea>");
}

function getLayersVisible() {
	// get layer visibility settings from cookie
	prefix = cookieName + "|";
	cookie = unescape(document.cookie);
	pos = cookie.indexOf(prefix);
	if (pos>=0) {
	    pos += prefix.length;
	    sep = cookie.indexOf(";");
	    if (sep == -1) sep = cookie.length;
	    var layerCookies = cookie.substring(pos, sep).split("|");
	    for (i=0; i<layerCookies.length; i++) {
	        sep = layerCookies[i].indexOf("=");
		name = layerCookies[i].substring(0, sep);
		value = layerCookies[i].substring(sep+1, layerCookies[i].length);
		if (Layers[name]) Layers[name].show = value;
		//alert("Read cookie: "+name+"="+value+" Layers["+name+"]="+Layers[name].show);
	    }
	}
}
function initCal(curmo) {

	// create default layer
	if (!Layers["default"]) DefineLayer("default", DefaultLayerFormat);
	
	// Default to current month and year
	mo = curmo;
	yr = GetFullYear(today);
	yearmonth = (yr * 100) + mo;

	// If querystring parameter is present, get the month/year ("calendar.htm?YYYYMM")
	if (location.search.length > 1) {
		yearmonth = parseInt(location.search.substring(1,location.search.length));
		if ((""+yearmonth).length == 6) {
			mo = yearmonth % 100;
			yr = (yearmonth - mo) / 100;
		}
	}

	// Constrain to the range of months with events
	if (yearmonth < FirstMonth) {
		mo = FirstMonth % 100;
		yr = (FirstMonth - mo) / 100;
		yearmonth = FirstMonth;
	}
	if (yearmonth > LastMonth) {
		mo = LastMonth % 100;
		yr = (LastMonth - mo) / 100;
		yearmonth = LastMonth;
	}
	gloMo = mo; gloYr = yr; gloYearmonth = yearmonth;
}

function qw(string) {
	return "&quot;" + string + "&quot;";
}

// Create a mini display of the desired month

function MiniMonth(yearmonth) {
	var bgn, firstday, lastdate, miniweek;
	var days = new arr("S","M","T","W","T","F","S");

	mo = yearmonth % 100;
	yr = (yearmonth - mo) / 100;
	bgn = new Date(months[mo] + " 1," + yr);
	// Get the day-of-week of the first day, and the # days in the month
	firstday = bgn.getDay();
	lastdate = NumDaysIn(mo,yr);
	document.write("<b><tt><Font Size=2><div align=center>&nbsp;" + months[mo] + "</div></font>");
	miniweek = "<font size=1>&nbsp;<u>";
	for (d in days) { miniweek += "&nbsp;" + days[d] + "&nbsp;"; }
	document.write(miniweek,"</u>");
	dy = 1;
	// Rest of the weeks . . .
	while (dy <= lastdate) {
		miniweek = "<br>";
		for (var i=1;i<=7;i++) {
			// If the day is less than the day of the week of the first day of the month, append spaces
			if (dy == 1 && i <= firstday){
				miniweek += "&nbsp;&nbsp;&nbsp;";
			// End minimonth if the day > last day of the month
			} else if (dy > lastdate) {
				break;
			// Otherwise, append date (w/ extra space for single digits)
			} else {
				miniweek += "&nbsp;" + ( dy<10 ? "&nbsp;" : "" ) +dy;
				dy++;
			}
		}
		document.write(miniweek);
	}
	document.write("</font></tt></b>");
}


// Remaining routines are utilities used above

function NumDaysIn(mo,yr) {
	if (mo==4 || mo==6 || mo==9 || mo==11) return 30;
	else if ((mo==2) && LeapYear(yr)) return 29;
	else if (mo==2) return 28;
	else return 31;
}

function LeapYear(yr) {
	return ( (yr%4 == 0 && yr%100 != 0) || yr % 400 == 0 ? true : false );
}

// fixes a Netscape 2 and 3 bug
function GetFullYear(d) { // d is a date object
	var yr = d.getYear();
	return ( yr < 1000 ? yr + 1900 : yr );
}

function PrevMonth(mth) {
	return ( mth == 1 ? 12 : mth - 1 );
}

function NextMonth(mth) {
	return ( mth == 12 ? 1 : mth + 1 );
}

function PrevYearMonth(yrmth) {
	return ( yrmth%100 == 1 ? yrmth-100+11 : yrmth-1 );
}

function NextYearMonth(yrmth) {
	return ( yrmth%100 == 12 ? yrmth-11+100 : yrmth+1 );
}

function JumpTo(calendar, thispage) {
	var sel, yrmo;


	sel = calendar.selectedIndex;
	//alert(sel);
	yrmo = calendar.form.jumpmonth[sel].value;
	//alert(thispage + "?" + yrmo);
	document.location = thispage + "?" + yrmo;
}

function BuildSelectionList(current, thispage) {
	var mo, yr, yearmonth;

	yearmonth = FirstMonth;
	tmp = "<form><select name=\"jumpmonth\" size=1 onchange=\"JumpTo(this,'" + thispage + "')\">";
	while (yearmonth <= LastMonth) {
		
		mo = yearmonth % 100;
		yr = (yearmonth - mo) / 100;
		//alert(yearmonth+" "+mo+" "+yr);
		selected = (yearmonth == current ? " selected" : "");
		tmp += "<option value=" + yearmonth + selected + ">" + months[mo]+" "+yr;
		yearmonth = NextYearMonth(yearmonth);
	}
  tmp += "</select></form>";
	return tmp;
}

// Create a message box

function DoMsgBox(yearmonth, msgSpan) {
	if (MsgBoxes[yearmonth]) {
		for (j in MsgBoxes[yearmonth]) { 	// find first unshown message for month that fits
			monthlyMsg =MsgBoxes[yearmonth][j];
			if (!monthlyMsg.shown) {
				//document.write("monthlyMsg.minspan = " + monthlyMsg.minspan + "<br>");
				if (!monthlyMsg.minspan || monthlyMsg.minspan <= msgSpan) {
					tmp = "<table border=2 bgcolor=" + msgBoxColor + " align=center>";
					tmp += "<TR><TD>"+ monthlyMsg.message + "</TD></TR></table>";
					document.write(tmp);
					monthlyMsg.shown = true;
					return;
				}
			}
		}
	}
	if (MsgBoxes[0]) { 	// show default MsgBox messages if they exists
		for (j in MsgBoxes[0]) { 	// find first unshown message for month that fits
			monthlyMsg =MsgBoxes[0][j];
			if (!monthlyMsg.shown) {
				//document.write("monthlyMsg.minspan = " + monthlyMsg.minspan + "<br>");
				if (!monthlyMsg.minspan || monthlyMsg.minspan <= msgSpan) {
					tmp = "<table border=2 bgcolor=" + msgBoxColor + " align=center>";
					tmp += "<TR><TD>"+ monthlyMsg.message + "</TD></TR></table>";
					document.write(tmp);
					monthlyMsg.shown = true;
					return;
				}
			}
		}
	}
}

// Utility routines

function escramVal(j,k){var a,b,c,d,e;a='<a href=\"mai';c='\">';a+='lto:';b=j+'@';e='</a>';b+=k;d=b;return(a+b+c+d+e);}

function parseFormat(format) {
	// pre and post are globals
	pre = post = "";
	if (format) {		
		var sep = format.indexOf("|");
		if (sep > 0) {  // split format into pre and post strings
			pre = format.substring(0, sep);
			post= format.substring(1+sep, format.length);
		}
	}
}

function CheckFormat(String) {
	var okay;
	okay =(String == "layer" || String == "custom" || String.indexOf("|")>0);
	if (!okay) alert("Invalid Calendar Format String: " + String);
	return okay;
}
	
// MsgBox constructor
function MsgBox(message,minspan,maxspan) {
	//alert("MsgBox("+message+","+minspan+","+maxspan+")");
	this.message = message;
	this.minspan = (minspan ? minspan : 1);
        if (maxspan) this.maxspan = maxspan;
	//this.shown = false;
}

function AddMsgBox(yearmonth,message,minspan,maxspan) {
	var i;

	if (!MsgBoxes[yearmonth]) MsgBoxes[yearmonth] = new Array;
	i = MsgBoxes[yearmonth].length;
	MsgBoxes[yearmonth][i] = new MsgBox(message,minspan,maxspan);
}

function ChooseLayers(yearmonth, thispage) {
	var i, checked;
	tmp = '<BR><form name="layerform"><b>Filter Events:</b>&nbsp;';
	for (i in Layers) {
		if (i != "default") {
			checked = (Layers[i].show == "true" ? " checked" : "");
			parseFormat(Layers[i].format);
			tmp += pre + '<input type="checkbox" name="' + i + '" value="' + i + '"' +checked + 
				' onClick="ChangeLayer(\''+i+'\')">' + i + "&nbsp;" + post;
		}
 	}
	//if (layerChange) {
	tmp += '&nbsp;<input type="button" name="ApplyChanges" value="Apply Changes"' +
		'onClick="ApplyLayerChange(\'' + thispage + '\',\'' + yearmonth + '\')">';
	//}
	
	document.write(tmp + "</form>");
}

function ChangeLayer(layer) {
	layerChange=true;
	Layers[layer].show = document.layerform[layer].checked;
}

function ApplyLayerChange(thispage, yearmonth) {
	layerChange=false;
	cookie = cookieName;
	for (layer in Layers) {
		if (layer != "default") {
			cookie += "|" + layer + "=" + Layers[layer].show;
		}
	}
	// persist cookie?
	document.cookie = escape(cookie);
	//alert("set cookie="+cookie);
	document.location = thispage + (yearmonth ? "?"+yearmonth : "");
}

// scrollable table stuff
//*****************************************************************************
// Filename: ScrollableTable.js
// Description: This javascript file can be applied to convert record tables
// in a HTML file to be scrollable.
// Version: 1.1
// Browser Compatibility: IE5.5+
//
// COPYRIGHT (C) 2002 WAGNER DOSANJOS
// THIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY IT
// UNDER THE TERMS OF THE GNU GENERAL PUBLIC LICENSE AS PUBLISHED BY THE FREE
// SOFTWARE FOUNDATION; EITHER VERSION 2 OF THE LICENSE, OR (AT YOUR OPTION)
// ANY LATER VERSION. THIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE
// USEFUL, BUT WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF
// MERCHANTABILITY OF FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU GENERAL
// PUBLIC LICENSE FOR MORE DETAILS.
//
// YOU SHOULD HAVE RECEIVED A COPY OF THE GNU GENERAL PUBLIC LICENSE ALONG
// WITH THIS PROGRAM; IF NOT, WRITE TO:
//
// THE FREE SOFTWARE FOUNDATION, INC.,
// 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
//
// Bugs/Comments: wanjos@yahoo.com
//
// Change History:
// 12-09-2002:
//  o Release v1.0
// 12-12-2002:
//  o Fixed: tHead and tFoot attributes not properly set after changing parent node.
//  o Fixed: Tables with 'width' attribute not properly handled.
//  o Release v1.1
//
//*****************************************************************************
// ScrollableTable.js
//
// This script contains useful functions that can be used to convert ordinary
// tables into scrollable tables.
//
// Here is how one can do that. The following assumptions are required
// for the tables to be sorted.
//
// 1. The table header should be defined in a TBODY.
// 2. The table footer (if one exists) should be defined in a TFOOT.
// 3. TD's in TBODY should not contain the width attribute.
//
// To enable the sorting, simply include this javascript source file and
// add an onLoad event to the <body> like below:
//
// <body onLoad="makeScrollableTable('table1',false,'auto');makeScrollableTable('table2',false,100); ...">
//
// Parameters:
//      - Table ID
//      - Scroll Footer (true/false): Include footer in the scrollable area
//      - Scrollable Area Height (# of pixels or 'auto'): Only the first table called can be set to 'auto'.
//
// Note that all the tables that need to be scrolled MUST contain an ID tag.
// So, if they do not exist, you must create one for each table. Also, the
// table names/ids MUST BE UNIQUE.
//*****************************************************************************
// Global variables
var container = new Array();
var onResizeHandler;

function scrollbarWidth(){
    var w;

    if (! document.body.currentStyle)   document.body.currentStyle = document.body.style;

    if (document.body.currentStyle.overflowY == 'visible' || document.body.currentStyle.overflowY == 'scroll'){
        w = document.body.offsetWidth - document.body.clientLeft - document.body.clientWidth;
    }else{
        win = window.open("about:blank", "_blank", "top=0,left=0,width=100,height=100,scrollbars=yes");
        win.document.writeln('scrollbar');
        w = win.document.body.offsetWidth - win.document.body.clientLeft - win.document.body.clientWidth;
        win.close();
    }

    return w;
}

function getActualWidth(e){
    if (! e.currentStyle)   e.currentStyle = e.style;

    return  e.clientWidth - parseInt(e.currentStyle.paddingLeft) - parseInt(e.currentStyle.paddingRight);
}

function findRowWidth(r){
    for (var i=0; i < r.length; i++){
        r[i].actualWidth = getActualWidth(r[i]);
    }
}

function setRowWidth(r){
    for (var i=0; i < r.length; i++){
        r[i].width = r[i].actualWidth;
        r[i].innerHTML = '<span style="width:' + r[i].actualWidth + ';">' + r[i].innerHTML + '</span>';
    }
}

function fixTableWidth(tbl){
    for (var i=0; i < tbl.tHead.rows.length; i++)   findRowWidth(tbl.tHead.rows[i].cells);
    findRowWidth(tbl.tBodies[0].rows[0].cells);
    if (tbl.tFoot)  for (var i=0; i < tbl.tFoot.rows.length; i++)   findRowWidth(tbl.tFoot.rows[i].cells);

    //tbl.width = '';

    for (var i=0; i < tbl.tHead.rows.length; i++)   setRowWidth(tbl.tHead.rows[i].cells);
    setRowWidth(tbl.tBodies[0].rows[0].cells);
    if (tbl.tFoot)  for (var i=0; i < tbl.tFoot.rows.length; i++)   setRowWidth(tbl.tFoot.rows[i].cells);
}



function makeScrollableTable(tbl,scrollFooter,height){
    var c, pNode, hdr, ftr, wrapper, rect;

    if (typeof tbl == 'string') tbl = document.getElementById(tbl);

    pNode = tbl.parentNode;
    fixTableWidth(tbl);

    c = container.length;
    container[c] = document.createElement('<SPAN style="height: 100; overflow: auto;">');
    container[c].id = tbl.id + "Container";
    pNode.insertBefore(container[c], tbl);
    container[c].appendChild(tbl);
    container[c].style.width = tbl.clientWidth + 2 * tbl.clientLeft + scrollbarWidth();

    hdr = tbl.cloneNode(false);
    hdr.id += 'Header';
    hdr.appendChild(tbl.tHead.cloneNode(true));
    tbl.tHead.style.display = 'none';

    if (!scrollFooter || !tbl.tFoot){
        ftr = document.createElement('<SPAN style="width:1;height:1;clip: rect(0 1 1 0);background-color:transparent;">');
        ftr.id = tbl.id + 'Footer';
        ftr.style.border = tbl.style.border;
        ftr.style.width = getActualWidth(tbl) + 2 * tbl.clientLeft;
        ftr.style.borderBottom = ftr.style.borderLeft = ftr.style.borderRight = 'none';
    }else{
        ftr = tbl.cloneNode(false);
        ftr.id += 'Footer';
        ftr.appendChild(tbl.tFoot.cloneNode(true));
        ftr.style.borderTop = 'none';
        tbl.tFoot.style.display = 'none';
    }

    wrapper = document.createElement('<table border=0 cellspacing=0 cellpadding=0>');
    wrapper.id = tbl.id + 'Wrapper';
    pNode.insertBefore(wrapper, container[c]);

    wrapper.insertRow(0).insertCell(0).appendChild(hdr);
    wrapper.insertRow(1).insertCell(0).appendChild(container[c]);
    wrapper.insertRow(2).insertCell(0).appendChild(ftr);

    wrapper.align = tbl.align;
    tbl.align = hdr.align = ftr.align = 'left';
    hdr.style.borderBottom = 'none';
    tbl.style.borderTop = tbl.style.borderBottom = 'none';

    // adjust page size
    if (c == 0 && height == 'auto'){
        onResizeAdjustTable();
        onResizeHandler = window.onresize;
        window.onresize = onResizeAdjustTable;
    }else{
        container[c].style.height = height;
    }
}

function onResizeAdjustTable(){
    if (onResizeHandler) onResizeHandler();

    var rect = container[0].getClientRects()(0);
    var h = document.body.clientHeight - (rect.top + (document.body.scrollHeight - rect.bottom));
    container[0].style.height = (h > 0) ? h : 1;
}

function printPage(){
    var tbs = document.getElementsByTagName('TABLE');
    var e;

    for (var i=0; i < container.length; i++)    container[i].style.overflow = '';

    window.print();

    for (var i=0; i < container.length; i++)    container[i].style.overflow = 'auto';
}
/* external_date_functions.js
*
* Purpose: Sample external date functions for JavaScript calendar
* Author: Richard Pike)
* Website: http://calendar.pikesys.com
*
* my_date returns an alternate date string corresponding to the given Gregorian date 
* my_holiday returns an appropriate holiday text string for the given Gregorian date
* my_alt_holiday returns an appropriate alternate holiday string for the given Gregorian date
*
*/

function makeArray() {
	this[0] = makeArray.arguments.length;
	for (i = 0; i < makeArray.arguments.length; i = i + 1)
		this[i+1] = makeArray.arguments[i];
}

var altMonthNames = new makeArray("Red", "Yellow", "Blue","Green","Purple","Orange","Cyan","Magenta","Goldenrod","Brown","Black","White");
var altMonths = new Array;

// altMonths constructor
function altMonth(startdate, monthnumber) {
	this.startdate = startdate;
	this.month = monthnumber;
}

function DefineAltMonth(startdate, monthnumber) {
	altMonths[altMonths.length] = new altMonth(startdate, monthnumber);
}

// these could be defined in external JavaScript such as altdates.js (the last altMonth defined will not show because endate is unknown!)
DefineAltMonth(20040404, 1);
DefineAltMonth(20040505, 2);
DefineAltMonth(20040606, 3);
DefineAltMonth(20040707, 4);
DefineAltMonth(20040808, 5);
DefineAltMonth(20040909, 6);
DefineAltMonth(20041010, 7);
DefineAltMonth(20041111, 8);
DefineAltMonth(20041212, 9);
DefineAltMonth(20050113, 10);
DefineAltMonth(20050214, 11);
DefineAltMonth(20050315, 12);
DefineAltMonth(20050416, 1);

function my_date(day, month, year, style) {
	if (!style) style = 0;
	var mo = 0;
	var dy, yr;
	var dateString = "";

	ymd = day + month*100 + year*10000;
	for (i=1; i<altMonths.length-1; i++) {
		if (ymd >= altMonths[i-1].startdate && ymd < altMonths[i].startdate) {
			mo = altMonths[i-1].month;
			startDay = altMonths[i-1].startdate%100;
			startMonth = ((altMonths[i-1].startdate-startDay)/100)%100;
			if (month == startMonth) {
				dy = day - startDay +1;
			} else {
				ym = month + year*100;
				prevYM = PrevYearMonth(ym);
				prevM = prevYM%100;
				prevY = (prevYM - prevM)/100;
				eom = NumDaysIn(prevM, prevY);
				dy = day + (eom - startDay +1);
			}
			yr = year - 1970;
			break;
		}
	}
	if (mo > 0) {
		if (style == 0) { 		// day monthnum year
			dateString = dy + ' ' + mo + ' ' + yr;
		} else if (style == 1) { 	// monthname year
			dateString = altMonthNames[mo] + ' ' + yr;
		} else if (style == 2) { 	// day monthname
			dateString = dy + ' ' + altMonthNames[mo];
		} else if (style == 3) { 	// monthname day
			dateString = altMonthNames[mo] + ' ' + dy;
		} else if (style == 4) { 	// day monthname year
			dateString = dy + ' ' + altMonthNames[mo] + ' ' + yr;
		}
	}
	return dateString;
}

function my_holiday(day, month, year) {
//alert("my_holiday("+day+","+month+","+year+")");
	var holString = "";
	// some American civil holidays
	if (month == 1 && day == 1) {
		holString = "New Year's Day";
	} else if (month == 6 && day == 14) {
		holString = "Flag Day";
	} else if (month == 7 && day == 4) {
		holString = "Independence Day";
	}else if (month == 12 && day == 25) {
		holString = "Merry Christmas";
	}
	return holString;
}

function my_alt_holiday(day, month, year) {
	var aday, amonth;
	var holString = "";
	
	// calculate alternate date from given Gregorian date
	var altDate = my_date(day, month, year);
	var altMonthYear = altDate.substring(altDate.indexOf(' ')+1, altDate.length);
	aday = eval(altDate.substring(0, altDate.indexOf(' ')));
	amonth = eval(altMonthYear.substring(0, altMonthYear.indexOf(' ')));
	
	if (aday == 1 ) {
		holString = "Happy " + altMonthNames[amonth];
	}
	return holString;
}

