/*
File:        calendar.js
Date:        26 August 2008
Author:      Paul VanLeeuwen
Copyright:   2008 Saint Joseph Catholic Church
Description: Calendar support functions.
*/
/*
Updates:
8-29-08:	Removed comma from calendar title, fixed cell height, added link to current month
8-30-08:	Added cache of previously generated calendars, rollover moreInfo functionality
8-30-08:	Added asynchronous request if a month is not cached, logic to populate the calendar with the returned liturgies.
9-02-08:    Fixed pop-up info for multiple liturgies in same month (problem with anonymous functions).
10-14-08:   Update to cache months on either side of current
10-28-08:   Changed liturgy href link to "javascript", instead of "#"
10-29-08:   Updated population of calendar to call function to display liturgy planning sheet
08-05-09:   Updated to use "getFullYear"
08-06-09:   Updated getSrcElement to also check target for Firefox
10-05-09:	Updated nextCalendar to work off of current calendar, rather than static variable
11-06-09:   Added nextSelectedCalendar to trigger from month and year pulldowns.
11-07-09:   Adjust month-at-a-glance query to provide planning table.
11-09-09:	Sort all liturgies by time.  (Corrected 3-27-2010)
04-26-10:   Provide parish ID instead of planning table.
*/

//Number of days in each month
maxDays = new Array (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
//Array of month names for display
months = new Array ("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
//AJAX object
var xObject = false;
if (window.XMLHttpRequest) {
	xObject = new XMLHttpRequest();
}
else if (window.ActiveXObject) {
	xObject = new ActiveXObject("Microsoft.XMLHTTP");
}

/*
function: isLeap
input:    year
output:   boolean indicating whether given year is a leapyear
process:  indicate if leapyear
*/
function isLeap(year) {
	if ((year % 4 == 0) && (year % 100 != 0)) {
		return true;
	}
	else if (year % 400 == 0) {
		return true;
	} else {
		return false;
	}
}

/*
function: compareLitTimes
input:    two elements of a liturgy array
output:   integer, negative for a before b, positive for b before a
process:  compare elements of a liturgy array, based on timestamp (HH:MM AM/PM)
*/
function compareLitTimes(litArrayA, litArrayB) {
	var liturgyA = litArrayA.split('|');
	var liturgyB = litArrayB.split('|');

	if (liturgyA[3] == undefined) return -1
	if (liturgyB[3] == undefined) return 1
	var timeA = liturgyA[3].split(" ");
	var timeB = liturgyB[3].split(" ");

	if (timeA[1] != timeB[1]) return (timeB[1]<timeA[1]) - (timeA[1]<timeB[1]);
	timeA = timeA[0].split(':');
	timeB = timeB[0].split(':');
	if (timeA[0] != timeB[0]) return timeA[0] - timeB[0];
	return timeA[1] - timeB[1];
}

/*
function: nextCalendar
input:    increment
output:   none
process:  add increment (positive or negative) to existing calendar adjustment; request update
          of calendar for corresponding month
*/
function nextCalendar (increment) {
	//Calculate requested month, generate the calendar
	var testDate
	if (increment == 0) {
		testDate = new Date();
	} else {	
		var newMonth = generateCalendar.currentMonth+increment;
		var yearAdjust = newMonth/12;
		yearAdjust = (yearAdjust >= 0) ? Math.floor(yearAdjust) : Math.ceil(yearAdjust);
		testDate = new Date(generateCalendar.currentYear+yearAdjust,newMonth%12,1);
	}
	generateCalendar(testDate);
}

/*
function: nextSelectCalendar
input:    none
output:   none
process:  Set current calendar based on pulldowns
*/
function nextSelectCalendar () {
	//Get date from pulldowns, generate the calendar
	var monthDisplay = document.getElementById("currentMonth")
	var yearDisplay = document.getElementById("currentYear")
	
	var testDate = new Date(yearDisplay.value,monthDisplay.value,1);
	generateCalendar(testDate);
}

/*
function: populateCalendarDates
input:    liturgyArray
output:   none
process:  Update the current calendar dates with appropriate liturgies
*/
function populateCalendarDates(liturgyArray) {
	for (i=1;i<liturgyArray.length;i++) {
		//For each liturgy, add anchor tag to appropriate date
		var liturgy = liturgyArray[i].split('|');
		var myDate = document.getElementById("date_"+liturgy[0]);
		myDate.appendChild(document.createElement('br'));
		var tempA = document.createElement('a');
		tempA.href = "javascript:;";
		tempA.innerHTML += liturgy[3];
		//Assign liturgy attributes for use by showMoreInfo function
		tempA.date = liturgy[0];
		tempA.massType = liturgy[1];
		tempA.description = liturgy[2];
		tempA.time = liturgy[3];
		tempA.table = liturgy[4];
		tempA.litID = liturgy[5];

		if (tempA.addEventListener) {
			tempA.addEventListener('mouseover', function (event) {showMoreInfo(event);},false);
			tempA.addEventListener('mouseout',hideMoreInfo,false);
			tempA.addEventListener('click', function (event) {showLiturgyPlanningSheet(event);},false);
		} else if (tempA.attachEvent) {
			tempA.attachEvent('onmouseover', function () {showMoreInfo(event);});
			tempA.attachEvent('onmouseout',hideMoreInfo);
			tempA.attachEvent('onclick', function () {showLiturgyPlanningSheet(event);});
		}
		myDate.appendChild(tempA);
	} //End for loop through all liturgies	
}

/*
function: generateCalendar
input:    testDate
output:   none
process:  Update the calendar (with 'calBody' id) for the month containing the input date
*/
function generateCalendar(testDate) {
	//Update month and year display
	generateCalendar.currentMonth = testDate.getMonth();
	generateCalendar.currentYear = testDate.getFullYear();
	
	//Set visibility of Return To Current Month link
	var todaysDate = new Date();
	var presentLink = document.getElementById("toPresent");
	if (generateCalendar.currentYear == todaysDate.getFullYear() && generateCalendar.currentMonth == todaysDate.getMonth()) {
		presentLink.style.visibility = "hidden";
	} else {
		presentLink.style.visibility = "visible";
	}
	
	var monthDisplay = document.getElementById("currentMonth")
	monthDisplay.value = testDate.getMonth();
	var yearDisplay = document.getElementById("currentYear")
	yearDisplay.value = testDate.getFullYear();
	
	//Retrieve the body of the calendar
	var tbody = document.getElementById("calBody");
	//Clear previous calendar if exists
	calendarCache.calendarGenerated = false;
	while(tbody.childNodes.length > 0) {
		tbody.removeChild(tbody.firstChild);	
	}
	//Check cache for this month
	var cachedMonth = calendarCache.getCachedMonth(testDate.getMonth(),testDate.getFullYear());
	
	//Generate calendar
	//Get first day of the given month, compute last day
	var firstOfMonth = new Date(testDate.getFullYear(),testDate.getMonth(),1);
	var numDays = maxDays[testDate.getMonth()];
	if (testDate.getMonth() == 1 && isLeap(testDate.getFullYear())) {
		numDays = 29;
	}
	var lastDayOfMonth = (firstOfMonth.getDay() + (numDays - 1)) % 7;
	
	//Create first row of calendar
	var cellHeight = 60;
	var date = 1;
	var firstRow = document.createElement('tr');
	for (i=0; i<firstOfMonth.getDay(); i++) {
		var day = document.createElement('td');
		day.innerHTML = "&nbsp";
		day.height = cellHeight;
		firstRow.appendChild(day);
	}
	for (i=firstOfMonth.getDay(); i<7; i++) {
		var day = document.createElement('td');
		day.innerHTML = date;
		day.id = "date_"+date++;
		day.height = cellHeight;
		firstRow.appendChild(day);
	}
	tbody.appendChild(firstRow);

	//Create middle, full rows
	while (date + 7 <= numDays) {
		var nextRow = document.createElement('tr');
		for (i=0; i<7; i++) {
			var day = document.createElement('td');
			day.innerHTML = date;
			day.id = "date_"+date++;
			day.height = cellHeight;
			nextRow.appendChild(day);
		}
		tbody.appendChild(nextRow);
	}

	//Create last row
	var lastRow = document.createElement('tr');
	for (i=0; i<=lastDayOfMonth; i++) {
		var day = document.createElement('td');
		day.innerHTML = date;
		day.id = "date_"+date++;
		day.height = cellHeight;
		lastRow.appendChild(day);
	}
	for (i=lastDayOfMonth+1; i<7; i++) {
		var day = document.createElement('td');
		day.innerHTML = "&nbsp";
		day.height = cellHeight;
		lastRow.appendChild(day);
	}
	tbody.appendChild(lastRow);
	
	//Extras - mark today!!!
	var todaysDate = new Date();
	if (testDate.getMonth() == todaysDate.getMonth() && testDate.getFullYear() == todaysDate.getFullYear()) {
		var myDate = document.getElementById("date_" + todaysDate.getDate());
		myDate.innerHTML += "<br/> Today!!!";
		myDate.style.backgroundColor = "#66FF66";
	}
		
	if (cachedMonth != "none") {
		//If retrieved cached month, populate
		populateCalendarDates(cachedMonth);
	}
	//Tell calendar cache to add dates from database
	calendarCache.calendarGenerated = true;
}

/*
Object: calendarCache
Purpose: Maintains cache of calculated months.
	getCachedMonth retrieves the requested month, reporting false if doesn't exist.
	getData receives the asynch response from server with requested dates, populates the calendar, and caches the result.
*/
var calendarCache = {
	cache: new Array(),
	calendarGenerated: false,
	//Retrieve month from the cache
	getCachedMonth: function (month, year) {	
		//Get requested month, sending request if necessary
		var cachedMonth = calendarCache.cache[year * 100 + month];
		if (cachedMonth == undefined) {
			//Issue httpRequest to get dates for this month
			xObject.open("GET", "scripts/monthAtAGlance.php?id=" + Number(new Date) + "&month=" + month + "&year=" + year + "&myParishID=" + parishID, true);
			xObject.onreadystatechange = calendarCache.getData;
			xObject.send(null);
			return "none";
		} else {
			if (month == generateCalendar.currentMonth && year == generateCalendar.currentYear) {
				calendarCache.cacheMore();
			}
			return cachedMonth;
		}
	},
	//Receive liturgy info from the database
	getData: function () {
		//Receive data from database, wait for calendarGenerated to go true, then populate liturgies (with popup)
		if (xObject.readyState == 4 && xObject.status == 200) {
			var replyText = xObject.responseText;

			if (replyText != "") {
				//alert(replyText);
				var liturgyArray = replyText.split("\n"); //Split return into an array - first row is date, rest are liturgies
				liturgyArray.sort(compareLitTimes); //sort by time
				//Cache generated month
				calendarCache.cache[liturgyArray[0]] = liturgyArray;
				//Request caching of liturgy planning sheets for this month
				liturgyCache.cacheLiturgies(liturgyArray);
				
				//If entry for current month, wait until calendar generated, then populate
				if (liturgyArray[0] == (generateCalendar.currentYear * 100 + generateCalendar.currentMonth)) {
					//Wait until the calendar is generated
					while (!calendarCache.calendarGenerated) {}
					populateCalendarDates(liturgyArray);
				}			
			} //End if not empty string
			calendarCache.cacheMore();
		} //End if successful status
	}, //End getData
	//Cache additional months
	cacheMore: function() {
		var currYear = generateCalendar.currentYear;
		var currMonth = generateCalendar.currentMonth;
		//Ensure months on either side of current are in cache
	    var cachedMonthTmp = calendarCache.getCachedMonth((currMonth+1)%12,Math.floor(currYear+((currMonth+1)/12)));

		if (cachedMonthTmp != "none") {
				if (currMonth==0) {																									
					cachedMonthTmp = calendarCache.getCachedMonth((currMonth-1)%12,currYear-1);
				} else {
					cachedMonthTmp = calendarCache.getCachedMonth((currMonth-1)%12,currYear);
				}
		}
	}//End cacheMore
}

/*
function: showMoreInfo
input:    event
output:   none
process:  Parses the input data into a pop-up, locates that pop-up relative to the mouse, and makes it visible,
          displaying extra information about a given liturgy
*/
function showMoreInfo(event) {
	//Populate more info pop-up with data
	var moreInfo = document.getElementById("moreInfo");
                var lit;
                if (event.target) lit = event.target;
                else if (event.srcElement) lit = event.srcElement;
                if (lit.nodeType == 3) //safari
                                lit = lit.parentNode;
	moreInfo.innerHTML = "<strong>" + lit.massType + "<br/>" + lit.description + "</strong><br/>" + months[generateCalendar.currentMonth] + " " + lit.date + " - " + lit.time;
	//Determine mouse position
	var posX = 0;
	var posY = 0;
	if (event.pageX || event.pageY) {
		posX = event.pageX;
		posY = event.pageY;
	} else if (event.clientX || event.clientY) {
		posX = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
		posY = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
	}
	//Set position of pop-up
	if (event.clientY < 70) {
		moreInfo.style.top = parseInt(posY)+60+"px";
	} else {
		moreInfo.style.top = Math.max(2,parseInt(posY)-70)+ "px";
	}
	moreInfo.style.left = Math.max(2,parseInt(posX)-130)+"px";
	//Make pop-up visible
	moreInfo.style.visibility = "visible";
}

/*
function: hideMoreInfo
input:    none
output:   none
process:  Hides the pop-up moreInfo window.
*/
function hideMoreInfo() {
	var moreInfo = document.getElementById("moreInfo");
	moreInfo.style.visibility = "hidden";
}
