//

//

// Enhanced JavaScript Event Calendar

//

// Author:  Rick Pike

// Website: http://calendar.pikesys.com

// Email: calendar@pikesys.com

// Developmental Version 20040911

//

// based on an earlier script by Kevin Ilsen (http://calendar.ilsen.net or kevin@ilsen.net)

//

// Permission is granted to use my adaptations in this script as long as the above information is included



// 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="#ffffcc";

var ColorSpecialDay = "red";

var BorderSpecialDay = "";

var CellSpecialDay = "#ffffcc";

var ReverseSpecialDay = false;

var OrderSpecialDay = 3;

var ColorHoliday = "red";

var BorderHoliday = "";

var CellHoliday = "#ffffcc";

var ReverseHoliday = false;

var OrderHoliday = 1;

var ColorAltHoly = "#999999";

var BorderAltHoly = ColorAltHoly;

var CellAltHoly = "#EEEEEE";

var ReverseAltHoly = true;

var OrderAltHoly = 2;

var ColorToday = "green";

var BorderToday = ColorToday;

var CellToday = "#CCFFCC";

var ReverseToday = true;

var OrderToday = 0;

var ColorEvent = "blue";

var BorderEvent = ColorEvent;

var CellEvent = "#CCDEE5"; //"#9999DD";

var ReverseEvent = false;

var OrderEvent = 4;

var ColorAltDate = "#999999";

var ColorMini = "black";

var ColorFade = "#CCCCCC";

var FadeAll = true;		// override holiday and special day highlighting

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 =true; 	// 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 = true; 	// 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 showNav = true; 		// enable month navigation (might disable for print version)

var showImages = true; 	// enable event images (might disable for print version)

var showLinks = true; 		// enable event hyperlinks (might disable for print version)

var formatLinks = false; 	// apply event format color to event hyperlinks superceding style color

var navColor = "#ffff99";

var msgBoxColor = "#ffcc99";

var msgBoxWidth = "";

var msgBoxBorder = 2;

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 = "layer"; // for compatibility; set to "layer" to simplify formatting

var ExportPage = ""; 		// name of html page for displaying event text for export

var ExportHolidays = true;	// export holidays in addition to events

var ExportAltHoly = true; 	// export alternate holidays in addition to events

var PrintPage = ""; 		// name of html page for printer-friendly format

var PrintPageRule = ""; 	// Text strings separated by a "|" to prepend and append to yearmonth to construct varying PrintPage (i.e. "print|.pdf")



// all format codes must have "|" to separate before and after tags

var DateFontSize=5;

var AltDateFormat = "<font color="+ColorAltDate+" size=2>|</font>";

var MonthFormat = "<font size=" + DateFontSize + "><b>|</b></font>";

var AltMonthFormat = "<br><font color="+ColorAltDate+" size=" + DateFontSize/2 + "><b>|</b></font>";

var HolidayFormat = "<font color="+ColorHoliday+" size=2><b><center>|</center></b></font>";

var AltHolyFormat = "<font color="+ColorAltHoly+" size=2><b><center>|</center></b></font>";

var DefaultLayerFormat = "<font color="+ColorEvent+" size=2>|</font>";

var MsgBoxFormat = "<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;

// var LastMonth=12+100*(curyr+1);



// 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;



// SpecialDays[] is an array of numbers corresponding to "special" days of the week (1=Sun, 2=Mon, ...)

// Call DefineSpecial() to populate it



var SpecialDays = new Array;



function DefineSpecial() {

	for (var n=0; n<DefineSpecial.arguments.length; n++) {

		SpecialDays[DefineSpecial.arguments[n]] = true;

	}

}



// 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;



// 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 (image) {

	   this.image = image;

	   if (width) this.width = width;

	   if (height) this.height = height;

	   if (align) this.align = align;

	   if (alt) this.alt = alt;

	}

	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, Color) {

	AddEvent(Date, Description, "", "", Link, Image, Width, Height, "", "");
}



function AddEvent(Date, Description, Layer, Format, Link, Image, Width, Height, Align, Alt) {

	var i;

	// WARNING: Leading zeros in Date will cause it to be interpreted as an octal number (base 8) and the date may be wrong on the calendar!

	//alert("AddEvent("+Date+", \"" + Description + ", \" + Layer + ",...)");

	if (!Events[Date]) Events[Date] = new Array;

	i = Events[Date].length;

	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

	if (Date > 1231) { 	// ignore dates without years

		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"



	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]; }

	this.length = arr.arguments.length;

	this.cycle = function () {

		var tmp = this[1];

		for (var n=2; n<=this.length; n++) { this[n-1] = this[n]; }

		this[this.length] = tmp;

	}

}



// Create the arrays of month and weekday names (used in various places)

var doAltNames = false;

var startWeekday = 1; 	// 1=Sunday, 2=Monday, etc.

var months = new arr("1¤ë","2¤ë","3¤ë","4¤ë","5¤ë","6¤ë","7¤ë","8¤ë","9¤ë","10¤ë","11¤ë","12¤ë");

var weekdays = new arr("¤é","¤@","¤G","¤T","¥|","¤­","¤»");

var days = new arr("S","M","T","W","T","F","S");

var words = new arr("", "¸õ¨ì«ü©w¤ë¥÷:", "Export Events Displayed", "Print-friendly", "Filter Events:","Apply Changes");

var alt_months = months;

var alt_weekdays = weekdays;

var alt_days = days;

var alt_words = words;



// Calendar( ) is the only routine that needs to be called to display the calendar

var cookieName = "layerCalendar";

var pre, post, tmp, gloMo, gloYr, gloYearmonth;

var inds = new Array(3); 	// this date every month, this date every year, and just this date

var msgdates = new Array(3); 	// every month, this month every year, and just this yearmonth



function Calendar( ) {

	var curyr, curmo, curdy, yr, mo, dy, firstday, yearmonth, bgn, lastdate, jump;

	var thispage = window.location.pathname;

	var myMsgBox = "Put this FREE calendar script on your own site; see <a href=http://calendar.pikesys.com>calendar.pikesys.com</a>.<p>";



	// Handle a single SpecialDay definition  (for compatability)

	if (SpecialDay) DefineSpecial(SpecialDay);



	// define default MsgBox messages

	//AddMsgBox(0, defaultMsgBox);

	//AddMsgBox(0, myMsgBox);

	

	// Save current day and month for comparison

	curdy = today.getDate();

	curmo = today.getMonth()+1;

	curyr = GetFullYear(today);

	

	initCal(curmo, curyr);

	mo = gloMo; yr = gloYr; yearmonth = gloYearmonth;

	getLayersVisible(); 		// get layer visibility settings from cookie

	

	// Create a date object for the first day of the desired month

	//bgn = new Date(months[mo] + " 1," + yr);

	bgn = new Date(yr, mo-1, 1);

	// Get the day-of-week of the first day, and the # days in the month

	//firstday = bgn.getDay();

	firstday = (bgn.getDay() + 8 - startWeekday)%7; 	// shift week start to specified day

	lastdate = NumDaysIn(mo,yr);

	lastday = 1+(firstday + lastdate - 1)%7;

	prev = next = "&nbsp;";

	

	if (showNav) {

		if (yearmonth > FirstMonth)

			prev = '<a class="navlink" href="' + thispage + '?'+PrevYearMonth(yearmonth)+'"><©¹¤W¤@¤ë '+'</a>';
			//prev = '<a class="navlink" href="' + thispage + '?'+PrevYearMonth(yearmonth)+'">&lt;-- '+words[1]+months[PrevMonth(mo)]+'</a>';

		if (yearmonth < LastMonth)

			next += '<a class="navlink" href="' + thispage + '?'+NextYearMonth(yearmonth)+'">©¹¤U¤@¤ë> '+'</a>';
			//next += '<a class="navlink" href="' + thispage + '?'+NextYearMonth(yearmonth)+'">'+words[1] +months[NextMonth(mo)]+' --&gt;</a>';

	}



	parseFormat(MonthFormat);

	tmp = "<TABLE  ALIGN=CENTER BORDER=1 BGCOLOR="+ColorBackground+" ><TR BORDER=0 BGCOLOR="+navColor+">";

	tmp += "<TD ALIGN=CENTER BGCOLOR="+navColor+">" + prev + "</TD>";

	//tmp += "<TD ALIGN=CENTER COLSPAN=5>" + pre + months[mo] + " " + yr + post;
	tmp += "<TD ALIGN=CENTER COLSPAN=5>" + pre + yr + "¦~ " + months[mo] + post;

	

	if (showAltDate) {

		parseFormat(AltMonthFormat);

		altMonth = getAltMonth(1, mo, yr, lastdate);

		tmp += pre + (altMonth ? altMonth : "") + post;

	}

	tmp += "</TD><TD ALIGN=CENTER BGCOLOR="+navColor+">" + next + "</TD></TR>";

	document.write(tmp);

	document.write("<TR BGCOLOR="+navColor+">");

	

	tmp = "";

	for (var i=1; i<=7; i++){

		tmp += "<TD ALIGN=CENTER WIDTH=14%" + (SpecialDays[i]&&CellSpecialDay ? " bgcolor="+CellSpecialDay : "") + ">";

		tmp += "<FONT SIZE=2" + (SpecialDays[i]&&ColorSpecialDay ? " color="+ColorSpecialDay : "") + ">"+weekdays[i]+"</FONT></TD>";

	}

	document.write(tmp + "</TR><TR>");



	dy = 1;

	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 BGCOLOR="+(SpecialDays[i] && CellSpecialDay ? CellSpecialDay : ColorBackground)+">");						

						MiniMonth(PrevYearMonth(yearmonth));

					} else {

						document.write("<TD>&nbsp;");

					}

				} else if (showMsgBox && i==2) { 	// span empty cells to allow messageBox

					msgSpan = firstday - 1;
				

					document.write("<TD BGCOLOR=" + ColorBackground + " COLSPAN=" + msgSpan +">&nbsp;");

					DoMsgBox(yearmonth, msgSpan);

				} else if (!showMsgBox) {

					document.write("<TD BGCOLOR="+(SpecialDays[i] && CellSpecialDay ? CellSpecialDay : ColorBackground)+">&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 BGCOLOR="+(SpecialDays[i] && CellSpecialDay ? CellSpecialDay : ColorBackground)+">");

						MiniMonth(NextYearMonth(yearmonth));

					} else {

						document.write("<TD"+ ">&nbsp;");

					}

				} else if (showMsgBox && i==(lastday+1)) { 	// span empty cells to allow messageBox.

					msgSpan = 6 - lastday;

					document.write("<TD BGCOLOR=" + ColorBackground + " COLSPAN=" + msgSpan +">&nbsp;");

					DoMsgBox(yearmonth, msgSpan);

				} else if (!showMsgBox) {

					document.write("<TD BGCOLOR="+(SpecialDays[i] && CellSpecialDay ? CellSpecialDay : ColorBackground)+">&nbsp;");

				}

				document.write("</TD>");



			// Otherwise, write date and the event, if any, in this cell of the table.

			} else {

				ShowDate(yr,mo,dy,i,curyr,curmo,curdy);

				dy++;

			}

		}

		document.write("</TR>");

	}

	if (showNav) {

		prev = next = "&nbsp;";

		if (yearmonth > FirstMonth)

			prev = '<a class="navlink" href="' + thispage + '?'+PrevYearMonth(yearmonth)+'"><©¹¤W¤@¤ë '+'</a>';
			//prev = '<a class="navlink" href="' + thispage + '?'+PrevYearMonth(yearmonth)+'">&lt;-- '+words[1]+months[PrevMonth(mo)]+'</a>';

		if (yearmonth < LastMonth)

			next += '<a class="navlink" href="' + thispage + '?'+NextYearMonth(yearmonth)+'">©¹¤U¤@¤ë> '+'</a>';
			//next += '<a class="navlink" href="' + thispage + '?'+NextYearMonth(yearmonth)+'">'+words[1]+months[NextMonth(mo)]+' --&gt;</a>';

		tmp = "<TR BGCOLOR="+navColor+"><TD ALIGN=CENTER BGCOLOR="+navColor+">" + prev + "</TD>";

		tmp += "<TD colspan=5 align=center valign=middle><FORM>";

		if (ExportPage) tmp += '<a class="navlink" href="' + ExportPage + '?'+yearmonth+'">'+words[3]+'</a>&nbsp;&nbsp;|&nbsp;&nbsp;';

		tmp += words[2] + '&nbsp;&nbsp;';

		document.write(tmp);

		BuildSelectionList(yearmonth, thispage);

		if (PrintPageRule) {

			parseFormat(PrintPageRule);

			PrintPage = pre + yearmonth + post;

		}

		if (PrintPage) document.write('&nbsp;&nbsp;|&nbsp;&nbsp;<a class="navlink" href="' + PrintPage + '?'+yearmonth+'">'+words[4]+'</a>');

		tmp = "</FORM></TD><TD ALIGN=CENTER BGCOLOR="+navColor+">" + next + "</TD>";

		document.write(tmp + "</TR>");

		if (layerCount>1) {

			document.write("<TR BGCOLOR="+navColor+"><TD colspan=7 align=center>");

			ChooseLayers(yearmonth, thispage);

			document.write("</TD></TR>");

		}

	}

	document.write("</TABLE>");

}



// Display a date in the appropriate color, with events (if there are any)



function ShowDate(yr, mo, dy, dayofweek, currentyear, currentmonth, currentday) {



	var ind, dayHighlight, dayReverse, borderHighlight, cellColor, tmp, event;



	dayHighlight = "";

	dayReverse = "";

	borderHighlight = "";

	cellColor = "";

	orderDay = 10;

	if ((yr == currentyear) && (mo == currentmonth) && (dy == currentday)) {

		orderDay = OrderToday;

		cellColor = CellToday;

		borderHighlight = BorderToday;

		if (ReverseToday) {

			dayHighlight = ColorBackground;

			dayReverse = ColorToday;

		} else {

			dayHighlight = ColorToday;

		}

	}

	// check for SpecialDay, AltHoly, and Holiday (in order of increasing precedence)

	if (SpecialDays[dayofweek] && OrderSpecialDay<orderDay) {

		orderDay = OrderSpecialDay;

		cellColor = CellSpecialDay;

		borderHighlight = BorderSpecialDay;

		if (ReverseSpecialDay) {

			dayHighlight = ColorBackground;

			dayReverse = ColorSpecialDay;

		} else {

			dayHighlight = ColorSpecialDay;

		}

	}

	if (showAltHoly) {

		if (getAltHoly(dy,mo,yr)  && OrderAltHoly<orderDay) {

			orderDay = OrderAltHoly;

			cellColor = CellAltHoly;

			borderHighlight = BorderAltHoly;

			if (ReverseAltHoly) {

				dayHighlight = ColorBackground;

				dayReverse = ColorAltHoly;

			} else {

				dayHighlight = ColorAltHoly;

			}

		}

	}

	if (showHolidays) {

		if (holidays(dy,mo,yr)  && OrderHoliday<orderDay) {

			orderDay = OrderHoliday;

			cellColor = CellHoliday;

			borderHighlight = BorderHoliday;

			if (ReverseHoliday) {

				dayHighlight = ColorBackground;

				dayReverse = ColorHoliday;

			} else {

				dayHighlight = ColorHoliday;

			}

		}

	}



	inds[0] = dy; 					// this date every month

	inds[1] = dy+100*mo; 				// this date every year

	inds[2] = dy+100*(mo+100*yr); 		// just this date



	for (var i in inds) { 	// this date every month, this date every year, just this date

		ind = inds[i];

		if (Events[ind]) {

			if (OrderEvent<orderDay) {	// today or special day take precedence

				orderDay = OrderEvent;

				cellColor = CellEvent;

				borderHighlight = BorderEvent;

				if (ReverseEvent) {

					dayHighlight = ColorBackground;

					dayReverse = ColorEvent;

				} else {

					dayHighlight = ColorEvent;

				}

			}

		}

	}



	if (ColorFade && yr == currentyear && mo==currentmonth && dy < currentday) dayHighlight = (FadeAll ? ColorFade : dayHighlight);



	document.write("<TD class='pik_cell' VALIGN=TOP" + (cellColor ? " bgcolor="+cellColor : "") + (borderHighlight ? " bordercolor="+borderHighlight : "") + ">");



	tmp = "<TABLE><TR VALIGN=TOP>";

	tmp += "<TD ALIGN=LEFT WIDTH=10% " + (dayReverse ? " bgcolor="+dayReverse : "") + ">";

	tmp += "<FONT SIZE=" + DateFontSize + (dayHighlight ? " COLOR=" + dayHighlight : "") + ">";

	tmp += "<B>" + dy + (dy<10 ? "&nbsp;" : "") + "&nbsp;</B></FONT></TD>";

	document.write(tmp);

	

	if (showAltDate) {

		altDate = getAltDate(dy, mo, yr);

		parseFormat(AltDateFormat);

		document.write("<TD ALIGN=RIGHT>" + pre + altDate + post + "</TD>");

	} else {

		document.write("<TD ALIGN=RIGHT></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 (var i in inds) { 	// this date every month, this date every year, just today

	ind = inds[i];

	for (var j in Events[ind]) {

		ev = Events[ind][j];

		// with(Events[ind][j]) { // greatly improves readability of following

		//for (var 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") {

			// Build the HTML string for this event

			tmp += (j>0 ? "<br>" : "");

			if (ev.image && showImages) {

				if (ev.link && showLinks) tmp += "<a class=\"eventlink\" href="+ev.link+">";

				if (ev.align) {

					align = ev.align;

				} else if (altAlign && images>0) {

					align = (lastAlign=="left" ? "right" : "left");

				} else {

					align = imageAlign;

				}

				tmp += '<img border=0 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++;

				if (ev.link && showLinks) tmp += "</a>";

			}

			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>";

			if (ev.link && showLinks) {

				hreftag = "<a class=\"eventlink\" href="+ev.link+">";

				if (formatLinks) {

					tmp += hreftag + pre + ev.description + post + "</a>" + "<br>";

				} else {

					tmp += pre + hreftag + ev.description + "</a>" + post + "<br>";

				}

			} else {

				tmp += pre + ev.description + post + "<br>";

			}

			

		} else {

			//alert("(-)skipping event for "+ind+" in layer "+ev.layer);

		}

	document.write("<FONT SIZE=1>" + tmp + "</FONT>");

	}

	}

	document.write("</TD>");

}



function exportCal( ) {

	var ind, curyr, curmo, curdy, yr, mo, firstday, yearmonth, lastdate, evdate;



	// Save current day and month for comparison

	curdy = today.getDate();

	curmo = today.getMonth()+1;

	curyr = GetFullYear(today);



	initCal(curmo, curyr);

	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);



	inds[0] = 0; 				// this date every month

	inds[1] = 0+100*mo; 			// this date every year

	inds[2] = 0+100*(mo+100*yr); 	// just this date



alert("exportCal: "+showAltHoly+","+ExportAltHoly+","+showHolidays+","+ExportHolidays);



	for (var dy=1; dy<=lastdate; dy++) {

		evdate = mo + "/" + dy + "/" + yr;



		if (showAltHoly && ExportAltHoly) {

			tmp = getAltHoly(dy,mo,yr);

			if (tmp) {

				alert("exportCal: exporting AltHoly " + tmp + " on " + evdate);

				document.write(qw(tmp) + "," + qw(evdate) + ",,,," + qw("true") + ",," + 

					qw("3") + "," + qw("CalendarScript-AltHoly") + "\n");

			}

		}



		if (showHolidays && ExportHolidays) {

			tmp = holidays(dy,mo,yr);

			if (tmp) {

				alert("exportCal: exporting Holidays " + tmp + " on " + evdate);

				document.write(qw(tmp) + "," + qw(evdate) + ",,,," + qw("true") + ",," + 

					qw("3") + "," + qw("CalendarScript-Holiday") + "\n");

			}

		}

	

		for (var i in inds) { 	// this date every month, this date every year, just this date

			ind = inds[i] + dy;

			for (var 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-Event");

					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 (var 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, curyr) {



	// create default layer

	if (!Layers["default"]) DefineLayer("default", DefaultLayerFormat);

	

	// Default to current month and year

	mo = curmo;

	yr = curyr;

	yearmonth = (yr * 100) + mo;



	// Handle non-English date names (weekdays & days defined as Sun to Sat even if startWeekday shift is specified)

	if (doAltNames) {

		for (var i=0; i<12; i++) { months[i+1] = alt_months[i+1]; }

		for (var i=0; i<7; i++) { weekdays[i+1] = alt_weekdays[i+1]; }

		for (var i=0; i<7; i++) { days[i+1] = alt_days[i+1]; }

		for (var i=0; i<words.length; i++) { words[i+1] = alt_words[i+1]; }

	}



	// shift week start to specified day

	if (startWeekday > 1) {

		for (var i=1; i<startWeekday; i++) {

			weekdays.cycle(); alt_weekdays.cycle();

			days.cycle(); alt_days.cycle();

		}

	}



	// 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;



	mo = yearmonth % 100;

	yr = (yearmonth - mo) / 100;

	//bgn = new Date(months[mo] + " 1," + yr);

	bgn = new Date(yr, mo-1, 1);

	// Get the day-of-week of the first day, and the # days in the month

	//firstday = bgn.getDay();

	firstday = (bgn.getDay() + 8 - startWeekday)%7; 	// shift week start to specified day

	lastdate = NumDaysIn(mo,yr);

	document.write("<b><tt><Font Size=2 color=" + ColorMini + "><div align=center>&nbsp;" + months[mo] + "</div></font>");

	miniweek = "<font size=1 color=" + ColorMini + ">&nbsp;<u>";

	for (var d=0; d<7; d++) { miniweek += "&nbsp;" + days[d+1] + "&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;

	yrmo = calendar.form.jumpmonth[sel].value;

	document.location = thispage + "?" + yrmo;

}



function BuildSelectionList(current, thispage) {

	var mo, yr, yearmonth;



	yearmonth = FirstMonth;

	tmp = "<select name=\"jumpmonth\" size=1 onchange=\"JumpTo(this,'" + thispage + "')\">";

	while (yearmonth <= LastMonth) {

		mo = yearmonth % 100;

		yr = (yearmonth - mo) / 100;

		selected = (yearmonth == current ? " selected" : "");

		tmp += "<option value=" + yearmonth + selected + ">" + yr +"¦~ "+ months[mo];
		//tmp += "<option value=" + yearmonth + selected + ">" + months[mo]+" "+yr;

		yearmonth = NextYearMonth(yearmonth);

	}



	document.write(tmp + "</select>");

}



// Create a message box



function DoMsgBox(yearmonth, msgSpan) {

	var showMsg;



	parseFormat(MsgBoxFormat);

	// check for MsgBox messages in the following order: this particular yearmonth, this month every year, every month

	msgdates[0] = yearmonth; 	// just this yearmonth

	msgdates[1] = yearmonth % 100; 	// this month every year

	msgdates[2] = 0; 	// every month	

	for (var k in msgdates) {

	if (MsgBoxes[msgdates[k]]) {

		for (var j in MsgBoxes[msgdates[k]]) { 	// find first unshown message for month that fits

			monthlyMsg = MsgBoxes[msgdates[k]][j];

			if (!monthlyMsg.shown) {

				//document.write("monthlyMsg.minspan = " + monthlyMsg.minspan + "<br>");

				showMsg = true; 	// show UNLESS one of the following size rules fail

				if (monthlyMsg.minspan && msgSpan < monthlyMsg.minspan) showMsg = false; 	// space too small

				if (monthlyMsg.maxspan && msgSpan > monthlyMsg.maxspan) showMsg = false; 	// space too big

				if (showMsg) {

					tmp = "<table class=\"pik_msgbox\" border=" + msgBoxBorder + " align=center bgcolor=" + msgBoxColor + (msgBoxWidth ? " width=" + msgBoxWidth : "") + ">";

					tmp += "<TR><TD>"+ pre + monthlyMsg.message + post + "</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 checked;

	tmp = '<form name="layerform"><b>' + words[5] + '</b>&nbsp;';

	for (var 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="' + words[6] + 

		'" 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 (var 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 : "");

}

function holidays(dy, mo, yr){


if (dy==1 && mo==7 && yr==2009) {
             return "¦^Âk¬ö©À¤é";
}
if (dy==1 && mo==10 && yr==2009) {
             return "°ê¼y¤é";
}
if (dy==3 && mo==10 && yr==2009) {
             return "¤¤¬î¸`";
}
if (dy==4 && mo==10 && yr==2009) {
             return "¤¤¬î¸`²Ý¤é";
}
if (dy==26 && mo==10 && yr==2009) {
             return "­«¶§¸`";
}
if (dy==25 && mo==12 && yr==2009) {
             return "¸t½Ï¸`";
}
if (dy==26 && mo==12 && yr==2009) {
             return "¸t½Ï¸`²Ý¤é";
     }
}
