﻿// wrapping the entire file in an anonymous function
(function () {

/**
 * Define POPUP global object. This will serve as the namespace for all
 * PopUp specific JavaScript.
 */
var POPUP;
if (typeof POPUP === "undefined") {
	POPUP = {};
} else if (typeof POPUP !== "object") {
	throw new Error("POPUP already exists but is not an object.");
} else {
	throw new Error("POPUP already exists as an object.");
}

POPUP.Dom = {
	/**
	 * Saves old window.onload functionality and adds our necessary onload functionality.
	 * Anything added to window.onload will not run until the page has fully loaded.
	 */
	onload: function (newWindowOnload) {
		var oldWindowOnload;
		if (window.onload) {
			// preserve old window.onload stuff
			oldWindowOnload = window.onload;
		}
		// now we can overwrite window.onload safely
		window.onload = function () {
			if (oldWindowOnload) {
				// execute old window.onload stuff
				oldWindowOnload();
			}
			// execute our init function
			newWindowOnload();
		};
	},
	// Collects all elements of a given class, under a given node, and of a given tag (element type) into an array.
	getElementsByClass: function (className, node, tag) {
		var classElements = [];
		if (!node) {
			node = document;
		}
		if (!tag) {
			tag = '*';
		}
		var els = node.getElementsByTagName(tag);
		var elsLen = els.length;
		var pattern = new RegExp('(^|\\s)' + className + '(\\s|$)');
		for (var i = 0, j = 0; i < elsLen; i++) {
			if (pattern.test(els[i].className)) {
				classElements[j] = els[i];
				j++;
			}
		}
		return classElements;
	}
};

POPUP.positionPopup = function (e) {
	if (!e) {
		e = window.event;
	}

	var mouseX = e.clientX;
	var mouseY = e.clientY;

	var winWidth = 0;
	var winHeight = 0;
	
	// deals with a positioning problem in IE7 when setting style.right
	var fudge = 10;
	
	if (typeof(window.innerWidth) === 'number') {
		winWidth = window.innerWidth;
		winHeight = window.innerHeight;
	} else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
		winWidth = document.documentElement.clientWidth;
		winHeight = document.documentElement.clientHeight;
	} else {
		winWidth = document.body.clientWidth;
		winHeight = document.body.clientHeight;
	}

	// Firefox supports window.pageYOffset, but IE supports document.body.scrollTop.
	var scrollY = window.pageYOffset;
	var scrollX = window.pageXOffset;
	if (scrollY === undefined) { //IE6
		scrollY = document.body.scrollTop;
		scrollX = document.body.scrollLeft;
		if (scrollY === 0) { //IE7
			scrollY = document.documentElement.scrollTop;
			scrollX = document.documentElement.scrollLeft;
			fudge = -10;
		}
	}

	if (mouseX > Math.floor(winWidth/2)) {
		POPUP.popup.style.left = 'auto';
		POPUP.popup.style.right = ((winWidth - e.clientX) - fudge - scrollX) + 'px';
	} else {
		POPUP.popup.style.right = 'auto';
		POPUP.popup.style.left = (e.clientX + 10 + scrollX) + 'px';
	}
	
	if (mouseY > Math.floor(winHeight/2)) {
		POPUP.popup.style.top = 'auto';
		POPUP.popup.style.bottom = ((winHeight - e.clientY) - scrollY) + 'px';
	} else {
		POPUP.popup.style.bottom = 'auto';
		POPUP.popup.style.top = (e.clientY + scrollY) + 'px';
	}
}

POPUP.sizePopup = function (e) {
	if (!e) {
		e = window.event;
	}
	POPUP.popup.style.maxWidth = '500px';
	POPUP.popup.style.overflow = 'hidden';
}

// Show the popup.
POPUP.showPopup = function (current, target, text, e) {
	if (!e) {
		e = window.event;
	}
	POPUP.popup.innerHTML = text;
	POPUP.popup.style.display = 'block';

	POPUP.sizePopup(e);
	POPUP.positionPopup(e);

	if (POPUP.isClickable) {
		document.onmouseover = function (e) {
			if (!e) {
				e = window.event;
			}
			// tg - element moving to
			var tg = (window.event) ? e.srcElement : e.target;
			// reltg - element moving from
			var reltg = (e.relatedTarget) ? e.relatedTarget : e.toElement;
			while (tg !== POPUP.popup && tg.nodeName != 'BODY') {
				tg = tg.parentNode;
			}
			// if the element we moved onto is the popup
			if (tg === POPUP.popup) {
				POPUP.enteredPopup = true;
				return;
			}
			while (reltg !== POPUP.popup && reltg.nodeName != 'BODY') {
				reltg = reltg.parentNode;
			}
			// if the element we moved off of is the popup
			if (reltg === POPUP.popup) {
				POPUP.enteredPopup = false;
				POPUP.clearPopup();
				document.onmouseover = null;
			}
		}
		current.onmouseout = function (e) {
			window.setTimeout(function () {
					if (!POPUP.enteredPopup) {
						POPUP.enteredPopup = false;
						POPUP.clearPopup();
						document.onmouseover = null;
					}
				},
				POPUP.hideAfter
			);
		}
	} else {
		document.onmousemove = function (e) {
			if (!e) {
				e = window.event;
			}
			POPUP.positionPopup(e);
		};
		current.onmouseout = function (e) {
			POPUP.clearPopup();
			document.onmousemove = null;
		};
	}
};

// Hide the popup.
POPUP.clearPopup = function () {
	POPUP.popup.style.display = 'none';
};

// Anything in init() waits until the page is done loading before it executes.
// We have to wait until then since our HTML code doesn't exist until that point.
// If we were to attempt to execute this code now, it would fail.
// For example, if we tried to do:
//   document.body.appendChild(popup);
// an error would occur since document.body doesn't even exist yet.
POPUP.init = function () {
	// Create a reusable popup element
	var popup = document.createElement('div');
	popup.id = 'popup';
	POPUP.popup = popup;

	// Should the popup element stick around so that it can be clicked on?
	// Set to true if you want people to be able to click on links inside of the
	// popup.
	POPUP.isClickable = false;

	// Number of milliseconds after which the popup should hide when POPUP.isClickable is set to true.
	POPUP.hideAfter = 1000;
	
	// Set prefix for classes and ids to look for.
	POPUP.prefix = 'help';
	POPUP.prefixWithSep = POPUP.prefix + '_';
	// Append the popup element to the body. This actually puts the popup element in the HTML.
	document.body.appendChild(popup);
	// Gather every <a class="help"> element.
	var helps = POPUP.Dom.getElementsByClass(POPUP.prefix, null);
	// Loop through all those elements.
	for (var i = 0; i < helps.length; i++) {
		// This is a self-invoking anonymous function.
		// Without this, our local (so-to-speak) variable would get clobbered, sort of.
		// Basically, all of our popups would contain the text from whatever the final <div class="help_hint"> element contains.
		// If you find all of this particularly interesting and confusing, as I once did, you know where to find me.
		(function () {
			var current = helps[i];
			// Get the id of the container we need to grab, which should be a class of the link (that the user will hover over), as POPUP.prefix + '_' + id
			var targetId = helps[i].getAttribute('class');
			targetId ? targetId = targetId : targetId = helps[i].getAttribute('className'); // IE
			if (targetId.match(POPUP.prefixWithSep)) {
				var startPos = targetId.search(POPUP.prefixWithSep);
				targetId = targetId.substr(startPos, targetId.length);
				targetId = targetId.replace(POPUP.prefixWithSep, '');
				var target = document.getElementById(targetId);
				if (target) {
					var text = target.innerHTML;
					// Attach event listeners.
					helps[i].onmouseover = function (e) {
						POPUP.showPopup(current, target, text, e);
					};
				}
			}
		}());
	}
};

POPUP.Dom.onload(POPUP.init);

})(); // end of anonymous function wrapper