/* Copyright 2012 Virtual Interconnect Software, LLC.  All rights reserved. */
function FXCalendarEventPreviewGetElementsByClassName(el, classNames) {
				if(el.getElementsByClassName)
				{
					return el.getElementsByClassName(classNames);
				}
				else
				{
					var names = classNames.split(" ");
					var allEls = el.getElementsByTagName("*");
					var outEls = [];
					for(var e = 0; e < allEls.length; ++e)
					{
						if(allEls[e].className)
						{
							var noMatch = false;
							for(var c = 0; c < names.length && !noMatch; ++c)
							{
								if((" " + allEls[e].className + " ").indexOf(" " + names[c] + " ") <= 0)
								{
									noMatch = true;
								}
							}
							if(!noMatch)
							{
								outEls.push(allEls[e]);
							}
						}
					}
					return outEls;
				}
			}

function FXCalendarEventPreviewGetEventEl(eventEl)
{
	while(eventEl && (" " + eventEl.className + " ").indexOf(" vevent ") < 0)
	{
		eventEl = eventEl.parentNode;
	}
	if(!eventEl)
	{
		return false;
	}
	return eventEl;
}

function FXCalendarEventPreviewPopup(eventEl)
{
	
	//set the timer to -1 to let the mouseout handler know that we're currently opening the preview
	delete eventEl.popupTimer;
	
	var getElementsByClassName = FXCalendarEventPreviewGetElementsByClassName;
	var parse8601Date = function(dateStr) {
				//parse an ISO-8601 date into a JS Date object
				var d = new Date();
				d.setUTCFullYear(dateStr.substring(0, 4));
				d.setUTCMonth(dateStr.substring(5, 7) - 1);
				d.setUTCDate(dateStr.substring(8, 10));
				d.setUTCHours(dateStr.substring(11, 13));
				d.setUTCMinutes(dateStr.substring(14, 16));
				d.setUTCSeconds(dateStr.substring(17, 19));
				var timestampWithoutOffset = d.getTime();
				var offset = dateStr.substring(19, dateStr.length);
				var offsetSeconds = (offset.length == 6 ? (offset.charAt(0) == "-" ? -1 : 1) * ((offset.substring(1, 3) * 60 * 60 * 1000) + (offset.substring(4, 6) * 60 * 1000)) : 0);
				var dateWithOffset = new Date(timestampWithoutOffset - offsetSeconds);
				return dateWithOffset;
			};
	var getPosition = function(el) {
				if(el.offsetParent && (!el.style || !el.style.overflow || (el.style.overflow != "scroll" && el.style.overflow != "auto")) && el.scrollLeft == 0 && el.scrollTop == 0 && el.tagName.toLowerCase() != "ol")
				{
					var parentPos = getPosition(el.offsetParent);
					return {x: el.offsetLeft + parentPos.x - el.scrollLeft, y: el.offsetTop + parentPos.y - el.scrollTop, rootNode: parentPos.rootNode};
				}
				else
				{
					return {rootNode: el, x: 0, y: 0};
				}
			};
	var formatTime = function(dateObj) {
				return (((dateObj.getHours() + 11) % 12) + 1) + ":" + (dateObj.getMinutes() < 10 ? "0" : "") + dateObj.getMinutes() + (dateObj.getHours() < 12 ? "am" : "pm");
			};
	var formatDate = function(dateObj) {
				var days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
				var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
				return days[dateObj.getDay()] + ", " + months[dateObj.getMonth()] + " " + dateObj.getDate() + ", " + dateObj.getFullYear();
			};
	var formatDateTime = function(dateObj) {
				return formatDate(dateObj) + " - " + formatTime(dateObj);
			};
	
	//figure out the microformat information for the event
	var summaryEl = getElementsByClassName(eventEl, "summary")[0];
	var dtstartEl = getElementsByClassName(eventEl, "dtstart")[0];
	var dtendEl = getElementsByClassName(eventEl, "dtend")[0];
	var categoriesEls = getElementsByClassName(eventEl, "categories");
	var sourceCalendarNameEls = getElementsByClassName(eventEl, "sourcecalendarname");
	
	//this one's optional, so don't try to access [0] yet
	var descriptionEls = getElementsByClassName(eventEl, "description");
	
	if(!eventEl.animateFunc)
	{
		//figure out where to align the bubble
		var scrollParentEl = eventEl;
		var coordsWithinScrollParent = { x: 0, y: 0 };
		while(scrollParentEl.offsetParent && (overflowStyle = (scrollParentEl.currentStyle ? scrollParentEl.currentStyle.overflow : (document.defaultView && document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(scrollParentEl, null).getPropertyValue("overflow") : true))) && overflowStyle != "auto" && overflowStyle != "scroll" && scrollParentEl.scrollLeft == 0 && scrollParentEl.scrollTop == 0)
		{
			coordsWithinScrollParent.x += scrollParentEl.offsetLeft;
			coordsWithinScrollParent.y += scrollParentEl.offsetTop;
			scrollParentEl = scrollParentEl.offsetParent;
		}
		if(!scrollParentEl.offsetParent)
		{
			//default to the box within its container
			coordsWithinScrollParent.x = eventEl.offsetLeft;
			coordsWithinScrollParent.y = eventEl.offsetTop;
			scrollParentEl = eventEl.offsetParent;
		}
		var alignment = (coordsWithinScrollParent.x / (scrollParentEl.offsetWidth - eventEl.offsetWidth));
		alignment = Math.max(0, Math.min(1, alignment));
		alignment = (((alignment - 0.5) * 0.88) + 0.5);
		
		//start constructing our bubble
		var borderColor = "#000";
		var bgColor = "#fff";
		var arrowSize = 15;
		var eventPos = getPosition(eventEl);
		var existingLinkEl = eventEl.getElementsByTagName("a")[0];
		var bubbleEl = document.createElement(existingLinkEl ? "a" : "div");
		if(existingLinkEl)
		{
			bubbleEl.style.display = "block";
			bubbleEl.setAttribute("href", existingLinkEl.getAttribute("href"));
			if(existingLinkEl.onclick)
			{
				bubbleEl.onclick = existingLinkEl.onclick;
			}
			bubbleEl.style.color = "#000";
			bubbleEl.style.outline = "0";
		}
		bubbleEl.style.fontSize = "small";
		bubbleEl.style.lineHeight = "125%";
		bubbleEl.style.color = "#000";
		var bubbleWidth = "21";
		var bubbleWidthUnits = "em";
		bubbleEl.style.position = "absolute";
		bubbleEl.style.left = (eventEl.clientWidth * 0.5) + "px";
		bubbleEl.style.top = (eventEl.clientHeight * 0.5) + "px";
		bubbleEl.style.width = 0;
		bubbleEl.style.height = 0;
		bubbleEl.zoom = 0;
		//there's a rendering bug in Firefox 3 where the triangle at the top of the info box renders as a rectangle when transforms are in effect
		if(navigator.appVersion.substring(0, navigator.appVersion.indexOf(".")) >= 4)
		{
			bubbleEl.style.MozTransform = "scale(0)";
		}
		bubbleEl.style.webkitTransform = "scale(0)";
		bubbleEl.style.opacity = 0;
		bubbleEl.style.zIndex = 500;
		eventEl.appendChild(bubbleEl);
		var arrowBGEl = bubbleEl.appendChild(document.createElement("div"));
		arrowBGEl.style.position = "absolute";
		arrowBGEl.style.left = -arrowSize + "px";
		arrowBGEl.style.top = -arrowSize + "px";
		arrowBGEl.style.borderTop = arrowSize + "px solid transparent";
		arrowBGEl.style.borderRight = arrowSize + "px solid transparent";
		arrowBGEl.style.borderBottom = arrowSize + "px solid " + borderColor;
		arrowBGEl.style.borderLeft = arrowSize + "px solid transparent";
		arrowBGEl.style.width = 0;
		arrowBGEl.style.height = 0;
		var textEl = bubbleEl.appendChild(document.createElement("div"));
		textEl.style.position = "absolute";
		textEl.style.borderRadius = "2em";
		textEl.style.MozBorderRadius = "2em";
		textEl.style.backgroundColor = bgColor;
		textEl.style.border = "2px solid " + borderColor;
		textEl.style.width = bubbleWidth + bubbleWidthUnits;
		textEl.style.left = -(bubbleWidth * alignment) + bubbleWidthUnits;
		if(alignment <= 0.13)
		{
			textEl.style.borderTopLeftRadius = 0;
			textEl.style.MozBorderTopLeftRadius = 0;
		}
		if(alignment >= 0.87)
		{
			textEl.style.borderTopRightRadius = 0;
			textEl.style.MozBorderTopRightRadius = 0;
		}
		textEl.style.top = arrowSize + "px";
		textEl.style.boxShadow = "3px 5px 10px rgba(0, 0, 0, 0.5)";
		textEl.style.MozBoxShadow = textEl.style.boxShadow;
		textEl.style.WebkitBoxShadow = textEl.style.boxShadow;
		var arrowEl = bubbleEl.appendChild(document.createElement("div"));
		arrowEl.style.position = "absolute";
		arrowEl.style.left = (-arrowSize) + "px";
		arrowEl.style.top = (-arrowSize + 3) + "px";
		arrowEl.style.borderTop = arrowSize + "px solid transparent";
		arrowEl.style.borderRight = arrowSize + "px solid transparent";
		arrowEl.style.borderBottom = arrowSize + "px solid " + bgColor;
		arrowEl.style.borderLeft = arrowSize + "px solid transparent";
		arrowEl.style.width = 0;
		arrowEl.style.height = 0;
		
		//now, start adding content
		var marginEl = textEl.appendChild(document.createElement("div"));
		marginEl.style.margin = "1em";
		var titleEl = marginEl.appendChild(document.createElement("h4"));
		titleEl.style.marginBottom = "0.5em";
		titleEl.appendChild(document.createTextNode(summaryEl.textContent));
		
		var dtStartObj = parse8601Date(dtstartEl.textContent);
		var dtStartDate = dtStartObj.toLocaleDateString();
		
		var dtEndObj = parse8601Date(dtendEl.textContent);
		var dtEndDate = dtEndObj.toLocaleDateString();
		
		var sameDate = (dtStartObj.getFullYear() == dtEndObj.getFullYear() && dtStartObj.getMonth() == dtEndObj.getMonth() && dtStartObj.getDate() == dtEndObj.getDate());
		var allDay = (dtStartObj.getHours() == 0 && dtStartObj.getMinutes() == 0 && dtStartObj.getSeconds() == 0 && dtEndObj.getHours() == 0 && dtEndObj.getMinutes() ==0 && dtEndObj.getSeconds() == 0);
		
		var tableEl = marginEl.appendChild(document.createElement("table"));
		var tbodyEl = tableEl.appendChild(document.createElement("tbody"));
		
		//generate string versions of start and end time
		var dtStartDisplay = "";
		var dtEndDisplay = "";
		if(!allDay)
		{
			dtStartDisplay = (sameDate ? formatTime(dtStartObj) : formatDateTime(dtStartObj));
			dtEndDisplay = (sameDate ? formatTime(dtEndObj) : formatDateTime(dtEndObj));
		}
		else
		{
			dtStartDisplay = formatDate(dtStartObj);
			dtEndDisplay = formatDate(new Date(dtEndObj.getTime() - 1000 * 60 * 60 * 12));
		}
		
		//display them
		var trEl = tbodyEl.appendChild(document.createElement("tr"));
		trEl.appendChild(document.createElement("td")).appendChild(document.createTextNode("Starts:"));
		trEl.appendChild(document.createElement("td")).appendChild(document.createTextNode(dtStartDisplay));
		var trEl = tbodyEl.appendChild(document.createElement("tr"));
		trEl.appendChild(document.createElement("td")).appendChild(document.createTextNode("Ends:"));
		trEl.appendChild(document.createElement("td")).appendChild(document.createTextNode(dtEndDisplay));
		
		//elapsed time
		if(!allDay)
		{
			var trEl = tbodyEl.appendChild(document.createElement("tr"));
			var elapsedSecondsTotal = (dtEndObj.getTime() - dtStartObj.getTime()) / 1000;
			var elapsedHours = Math.floor(elapsedSecondsTotal / 60 / 60);
			var elapsedMinutes = Math.floor(elapsedSecondsTotal / 60 % 60);
			var elapsedSeconds = Math.floor(elapsedSecondsTotal % 60);
			trEl.appendChild(document.createElement("td")).appendChild(document.createTextNode("Length of time:"));
			trEl.appendChild(document.createElement("td")).appendChild(document.createTextNode((elapsedHours > 0 ? elapsedHours + "h " : "") + (elapsedMinutes > 0 ? elapsedMinutes + "m " : "") + elapsedSeconds + "s"));
		}
		else
		{
			var trEl = tbodyEl.appendChild(document.createElement("tr"));
			var tdEl = trEl.appendChild(document.createElement("td"));
			tdEl.setAttribute("colspan", 2);
			tdEl.appendChild(document.createTextNode("All-day event"));
		}
		
		//categories
		if(categoriesEls.length > 0 && categoriesEls[0].childNodes.length > 0)
		{
			var trEl = tbodyEl.appendChild(document.createElement("tr"));
			var tdEl = trEl.appendChild(document.createElement("td"));
			tdEl.style.verticalAlign = "top";
			tdEl.appendChild(document.createTextNode("Categories:"));
			var ulEl = trEl.appendChild(document.createElement("td")).appendChild(document.createElement("ul"));
			ulEl.style.listStyle = "none";
			ulEl.style.margin = 0;
			ulEl.style.padding = 0;
			for(var c = 0; c < categoriesEls[0].childNodes.length; ++c)
			{
				var liEl = ulEl.appendChild(document.createElement("li"));
				var imgEl = liEl.appendChild(categoriesEls[0].childNodes[c].firstChild.cloneNode(true));
				imgEl.style.marginRight = "0.5em";
				liEl.appendChild(document.createTextNode(categoriesEls[0].childNodes[c].firstChild.getAttribute("title")));
			}
		}
		
		//assignment
		if(sourceCalendarNameEls.length > 0)
		{
			var trEl = tbodyEl.appendChild(document.createElement("tr"));
			var tdEl = trEl.appendChild(document.createElement("td"));
			tdEl.style.verticalAlign = "top";
			tdEl.appendChild(document.createTextNode("Assigned:"));
			var tdEl = trEl.appendChild(document.createElement("td"));
			tdEl.appendChild(document.createTextNode(sourceCalendarNameEls[0].textContent));
		}
		
		if(descriptionEls.length > 0)
		{
			//we have a description to display
			var descriptionEl = marginEl.appendChild(document.createElement("div"));
			descriptionEl.style.marginTop = "1em";
			var lines = descriptionEls[0].textContent.replace(/^\s*/, "").split("\n");
			for(var l = 0; l < lines.length; ++l)
			{
				if(l != 0)
				{
					descriptionEl.appendChild(document.createElement("br"));
				}
				descriptionEl.appendChild(document.createTextNode(lines[l]));
			}
		}
		
		eventEl.popupBubble = bubbleEl;
		
		if(typeof CalendarAddBubbleButtons != "undefined")
		{
			CalendarAddBubbleButtons(marginEl);
		}
		
		//start animating
		eventEl.animateFunc = function() {
					eventEl.popupBubble.zoom = (eventEl.popupBubble.zoom * 0.5) + (eventEl.zoomTarget * 0.5);
					
					//if we're close enough to the end, snap to it and finish up
					if(Math.abs(eventEl.popupBubble.zoom - eventEl.zoomTarget) < 0.001)
					{
						eventEl.popupBubble.zoom = eventEl.zoomTarget;
						clearInterval(eventEl.animateInterval);
						eventEl.animateInterval = null;
					}
					//there's a rendering bug in Firefox 3 where the triangle at the top of the info box renders as a rectangle when transforms are in effect
					if(navigator.appVersion.substring(0, navigator.appVersion.indexOf(".")) >= 4)
					{
						eventEl.popupBubble.style.MozTransform = "scale(" + eventEl.popupBubble.zoom + ")";
					}
					eventEl.popupBubble.style.webkitTransform = "scale(" + eventEl.popupBubble.zoom + ")";
					eventEl.popupBubble.style.opacity = eventEl.popupBubble.zoom;
				};
	}
	if(!eventEl.animateInterval)
	{
		eventEl.animateInterval = setInterval(eventEl.animateFunc, 40);
	}
	eventEl.zoomTarget = 1;
}

function FXCalendarEventPreviewPopdown(eventEl)
{
	//clear the timer - we're already currently executing under it
	delete eventEl.popupTimer;
	eventEl.zoomTarget = 0;
	if(!eventEl.animateInterval)
	{
		eventEl.animateInterval = setInterval(eventEl.animateFunc, 40);
	}
}

function FXCalendarEventPreviewOver(e)
{
	if(!e) { e = window.event; }
	
	var sourceEl = FXCalendarEventPreviewGetEventEl(window.event ? e.srcElement : e.target);
	var destEl = FXCalendarEventPreviewGetEventEl(e.relatedTarget ? e.relatedTarget : e.toElement);
	if(sourceEl == destEl)
	{
		return false;
	}
	
	var eventEl = FXCalendarEventPreviewGetEventEl(e.target);
	
	//wait 0.5 seconds before popping open a preview of the event
	//this gives our visitor a chance to move the mouse off of the event first
	if(typeof eventEl.popupTimer == "undefined" || eventEl.popupTimer == -1)
	{
		eventEl.popupTimer = setTimeout(function() { FXCalendarEventPreviewPopup(eventEl); }, 500);
	}
	else
	{
		clearTimeout(eventEl.popupTimer);
		delete eventEl.popupTimer;
	}
}

function FXCalendarEventPreviewOut(e)
{
	if(!e) { e = window.event; }
	
	var sourceEl = FXCalendarEventPreviewGetEventEl(window.event ? e.srcElement : e.target);
	var destEl = FXCalendarEventPreviewGetEventEl(e.relatedTarget ? e.relatedTarget : e.toElement);
	if(sourceEl == destEl)
	{
		return false;
	}
	
	var eventEl = FXCalendarEventPreviewGetEventEl(e.target);
	
	//if it's open, wait 1 second before popping it closed
	if(typeof eventEl.popupTimer == "undefined" || eventEl.popupTimer == -1)
	{
		eventEl.popupTimer = setTimeout(function() { FXCalendarEventPreviewPopdown(eventEl); }, 1000);
	}
	else
	{
		clearTimeout(eventEl.popupTimer);
		delete eventEl.popupTimer;
	}
}

function FXCalendarEventPreview()
{
	//when a visitor mouses over an event, pop up a small info box for the event based on the hCalendar microformat info
	//getElementsByClassName is used quite extensively since we're processing a microformat, so make sure we have a consistent function to use
	var getElementsByClassName = FXCalendarEventPreviewGetElementsByClassName;
	
	//first, locate all calendars that we can apply this effect to
	//we can only apply this to calendars that have embedded hCalendar microformat data
	var calendars = getElementsByClassName(document, "CalendarMonth vcalendar");
	
	//for each calendar, apply the mouseover behavior to each event element
	for(var c = 0; c < calendars.length; ++c)
	{
		var events = getElementsByClassName(calendars[c], "vevent");
		for(var e = 0; e < events.length; ++e)
		{
			events[e].onmouseover = FXCalendarEventPreviewOver;
			events[e].onmouseout = FXCalendarEventPreviewOut;
		}
	}
}

RegisterInit("FXCalendarEventPreview();");

