/*
 * common.js
 *
 *
 * Common JavaScript file used by every page on the website.
 *
 *
 * Written by Arimah
 * http://arimah.beoch.net/
 *
 *
 * Do not use without permission.
 */

Math.sign = function(a) { return a < 0 ? -1 : a > 0 ? 1 : 0; };
Math.ensureInRange = function(min, max, value) { return value < min ? min : value > max ? max : value; };
Math.round2 = function(x, decimals) { var m = Math.pow(10,decimals); return Math.round(x*m)/m; };

var imgPathPrefix = "/img/";
var preloadImages = [ "pbox_corners.png", "pbox_hsides.png", "pbox_vsides.png" ];

var currentMedia = "screen";

function initPage() {
	if (initPage.hasRun) return;

	var mediaDeterminer = document.getElementById("mediadeterminer");
	if (window.getComputedStyle) { // W3C
		currentMedia = window.getComputedStyle(mediaDeterminer, "").zIndex == "1" ? "screen" : "handheld";
	} else if (mediaDeterminer.currentStyle) { // IE
		currentMedia = mediaDeterminer.currentStyle.zIndex == "1" ? "screen" : "handheld";
	}
	if (currentMedia != "screen") return; // don't do anything for mobiles!

	// must init headings first, else nodes will be uninitialized
	var headings = document.getElementsByTagName("h2");
	for (var i = 0; i < headings.length; i++) {
		var h = headings[i], id;
		if ((id = h.getAttribute("id")) && id != "topic") {
			h.innerHTML = '<span class="node small unlabeled"><a href="#'+id+'" rel="in-page" title="'+ST.sectionlink+'">'+
				'<span class="image"></span><br/><span class="label"></span></a></span>'+h.innerHTML;
		}
	}

	var elems = document.getElementsByTagName("*"); // yes, yes, yes, I know, I know
	var elemsLen = elems.length;
	for (var i = 0; i < elemsLen; i++) {
		var elem = elems[i];
		if (!elem || elem.nodeType != 1) continue;
		if (hasClass(elem, "node") && hasClass(elem, "unlabeled"))
			initNode(elem);
	}

	initNav();
	initXnav();
	initSettings();
	initTopLink();

	initEgg();

	initPage.hasRun = true;
}

// 'node' is a <div> or <span>
function initNode(node) {
	var anchor = node.getElementsByTagName("a")[0];
	var spanImage      = null;
	var spanLabel      = null;
	var spanLabelshown = null;
	var fullLabel      = "";
	var fromTitle      = false;

	var spans = node.getElementsByTagName("span");
	for (var i = 0; i < spans.length; i++) {
		if (hasClass(spans[i], "image"))
			spanImage = spans[i];
		else if (hasClass(spans[i], "label"))
			spanLabel = spans[i];
		if (spanImage && spanLabel)
			break;
	}

	spanLabelshown = document.createElement("span");
	spanLabelshown.className = "labelshown";
	spanLabel.parentNode.insertBefore(spanLabelshown, spanLabel);

	if (fullLabel = anchor.getAttribute("title"))
		fromTitle = true;
	else
		fullLabel = spanLabel.innerHTML;

	var animIntervalId = null;
	var i = 1;
	spanImage.onmouseover = function() {
			spanLabelshown.style.display = "inline";
			spanLabelshown.innerHTML = fullLabel.substr(0, 1);
			animIntervalId = window.setInterval(function() {
					if (i < fullLabel.length) {
						spanLabelshown.innerHTML = fullLabel.substr(0, i);
						if (!fromTitle)
							spanLabel.innerHTML = fullLabel.substr(i, fullLabel.length-i);
						i++;
					} else {
						spanLabelshown.innerHTML = fullLabel;
						if (!fromTitle)
							spanLabel.innerHTML = "";
						window.clearInterval(animIntervalId);
					}
				}, 25);
		};
	spanImage.onmouseout = function() {
			spanLabelshown.style.display = "none";
			spanLabelshown.innerHTML = "";
			if (!fromTitle)
				spanLabel.innerHTML = fullLabel;
			window.clearInterval(animIntervalId);
			i = 1;
		};
}
// initializes #nav, which becomes floating when it has to
function initNav() {
	if (readCookie("menustyle") == "fixed") return;

	var divNav = document.getElementById("nav");
	if (!divNav)
		return;

	var navHeight  = divNav.offsetHeight;
	var topDefault = 80;  // style.css: #nav { top: 80px; }
	var getThreshold = function() {
			var windowHeight = getWindowHeight();
			if (windowHeight < navHeight+topDefault+10) {
				return Math.max(windowHeight - navHeight - 10, 0);
			} else {
				return topDefault-10;
			}
		};
	var moveTo = function(target) {
			moveTo.target = target;
			if (!moveTo.moving && moveTo.target != moveTo.current) {
				moveTo.moving = true;
				moveTo.animId = window.setInterval(function() {
						if (moveTo.current == moveTo.target) {
							window.clearInterval(moveTo.animId);
							moveTo.moving = false;
							return;
						}

						var yScroll = getYScroll();
						var windowHeight = getWindowHeight();
						if (moveTo.current+navHeight < yScroll)
							moveTo.current = yScroll-navHeight;
						else if (moveTo.current > yScroll+windowHeight)
							moveTo.current = yScroll+windowHeight;

						var dy = (moveTo.target-moveTo.current)/6;
						if (Math.abs(dy) < 1)
							dy = Math.sign(dy);
						else if (Math.abs(dy) > 12)
							dy = Math.sign(dy)*12;

						moveTo.current += Math.floor(dy);
						divNav.style.top = moveTo.current+"px";
					}, 10);
			}
		};
	moveTo.current = topDefault;

	var divFrame = document.getElementById("frame");
	window.setInterval(function() {
			//var scroll = getYScroll();
			//var threshold = getThreshold();
			moveTo(Math.ensureInRange(getThreshold()+10, divFrame.offsetHeight-navHeight-10, getYScroll()+10));
		}, 100);
}
// initializes #xnav, if there is one
function initXnav() {
	var xntoggle = document.getElementById("xntoggle");
	if (!xntoggle)
		return;

	var xnwrapper = document.getElementById("xnwrapper");
	var xnWidth   = xnwrapper.offsetWidth;

	var curPosition = 0;
	var curDX = 0; // 1 = hide; -1 = show
	var xnAnimId;

	var showXnavFunc = function() {
			if (curPosition == 0) {
				curDX = -1;
				window.clearInterval(xnAnimId); // stop animation
				return;
			}

			if (curPosition > xnWidth / 2) { // speed up
				curDX = 1.63*curDX;
			} else {  // slow down
				curDX = curDX/1.63;
			}
			curDX = Math.min(curDX, -1);
			curPosition = Math.max(Math.round(curPosition+curDX), 0); // don't go past 0
			xnwrapper.style.marginRight = (-curPosition)+"px";
		};
	var hideXnavFunc = function() {
			if (curPosition == xnWidth) {
				curDX = 1;
				xnwrapper.style.display = "none"; // ensure hidden
				window.clearInterval(xnAnimId); // stop animation
				return;
			}

			if (curPosition > xnWidth / 2) { // slow down
				curDX = curDX/1.63;
			} else {  // speed up
				curDX = 1.63*curDX;
			}
			curDX = Math.max(curDX, 1);
			curPosition = Math.min(Math.round(curPosition+curDX), xnWidth); // don't go past target width
			xnwrapper.style.marginRight = (-curPosition)+"px";
		};
	var toggleTopics = function(forcedValue) {
			window.clearInterval(xnAnimId); // always stop previous animation
			if (typeof forcedValue == "undefined" || forcedValue == 0)
				curDX = -curDX; // toggle
			else if (Math.sign(forcedValue) != Math.sign(curDX))
				curDX = Math.sign(curDX) == 0 ? Math.sign(forcedValue) : -curDX; // change sign

			if (curDX > 0) { // hide
				xnAnimId = window.setInterval(hideXnavFunc, 25);
			} else { //show
				xnwrapper.style.display = "block"; // ensure visible
				xnAnimId = window.setInterval(showXnavFunc, 25);
			}
		};

	xntoggle.onclick = function() {
			toggleTopics();
			return false;
		};
	xntoggle.onmousedown = xntoggle.onmouseup = function() { return false; };
	toggleTopics(1); // start shown, but hide right away
}

function initSettings() {
	var box = {}; // lightbox
	initSettingsBox(box);

	var settingsnode = document.getElementById("settingsnode");
	var anchor = settingsnode.getElementsByTagName("a")[0];
	anchor.onclick = function() {
			box.show();
			return false;
		};
}
function initSettingsBox(box) {
	var body = document.body || document.getElementsByTagName("body")[0];
	box.state = 0; // 0 = closed; 1 = toggling; 2 = open

	var setOpacity = function(elem, value, max) {
			value = Math.ensureInRange(0, max, value);
			elem.curOpacity = value;
			elem.style.opacity = value/100;
			try {
				elem.filters.alpha.opacity = value;
			} catch(e) {}
		};

	var fadeIntervalId;
	box.show = function() {
			if (box.state != 0) // closed
				return;

			// create DOM
			box.overlay = document.createElement("div");
			box.overlay.setAttribute("id", "lboverlay");
			box.overlay.onclick = function() { box.close(); };
			body.appendChild(box.overlay); // don't forget to insert into document!

			box.div = document.createElement("div"); // settings box
			box.div.setAttribute("id", "settings");
			box.div.parentBox = box;
			initSettingsDiv(box.div);
			body.appendChild(box.div);

			box.div.scrollIntoView();

			// fade in
			box.state = 1; // toggling
			box.overlay.style.display = "block";
			box.overlay.style.filter = "alpha(opacity=0)";
			setOpacity(box.overlay, 0, 80);
			box.div.style.display = "block";
			box.div.resizeAnimate(Math.min(500, getWindowWidth()-50),
				Math.min(box.div.contentArea.offsetHeight, getWindowHeight()-50), false,
				function() {
					box.div.contentArea.parentNode.style.overflow = "auto";
					box.div.ensureCentered.startMonitor();
				});
			fadeIntervalId = window.setInterval(function() {
					setOpacity(box.overlay, box.overlay.curOpacity+10, 80);
					if (box.overlay.curOpacity == 80) {
						window.clearInterval(fadeIntervalId);
						box.state = 2; // open
					}
				}, 20);
		};
	box.close = function() {
			if (box.state == 0) // closed - no DOM exists for box
				return;
			
			window.clearInterval(fadeIntervalId);
			box.state = 1; // toggling
			box.div.ensureCentered.stopMonitor();
			box.div.contentArea.parentNode.style.overflow = "hidden";
			box.div.resizeAnimate(0, 0, true,
				function() {
					box.div.style.display = "none";
					body.removeChild(box.div);
				});
			fadeIntervalId = window.setInterval(function() {
					setOpacity(box.overlay, box.overlay.curOpacity-10, 80);
					if (box.overlay.curOpacity == 0) {
						window.clearInterval(fadeIntervalId);
						box.destroyDOM();
						box.state = 0; // closed
					}
				}, 20);
		};
	box.destroyDOM = function() {
			if (box.state == 0) // closed - no DOM exists for box
				return;
			
			box.overlay.style.display = "none";
			body.removeChild(box.overlay);
		};
}
function initSettingsDiv(div) {
	var cookiesEnabled = testCookies();

	div.appendChild(document.createElement("hr"));
	var decorClasses = [ "n w", "n middle", "n e", "w middle", "e middle", "s w", "s middle", "s e" ];
	for (var i = 0; i < decorClasses.length; i++) {
		var decor = document.createElement("div");
		decor.className = decorClasses[i];
		div.appendChild(decor);
	}

	var scrollArea = document.createElement("div");
	scrollArea.setAttribute("id", "sbscrollarea");
	div.appendChild(scrollArea);

	var content = document.createElement("div");
	div.contentArea = content;
	content.setAttribute("id", "sbcontent");
	scrollArea.appendChild(content);

	content.appendChild(document.createElement("h2")).innerHTML = ST.settings_title; // appendChild returns appended child
	var note = document.createElement("p");
	note.className = "note";
	note.innerHTML = ST.settings_top;
	content.appendChild(note);
	if (!cookiesEnabled) {
		var warning = document.createElement("div");
		warning.setAttribute("id", "nocookiewarning");
		warning.innerHTML = ST.cookiewarning;
		content.appendChild(warning);
	}

	var settings = [
			{ "id": "s_fixedmenu", "label": ST.fixnav_checkbox, "desc": ST.fixnav_desc,
				"cookie": ["menustyle", "fixed", "scroll"] },
			{ "id": "s_usexsampa", "label": ST.altphon_checkbox, "desc": ST.altphon_desc,
				"cookie": ["phonetics", "xsampa", "ipa"] },
			{ "id": "s_disablepreview", "label": ST.nopreview_checkbox, "desc": ST.nopreview_desc,
				"cookie": ["preview", "disabled", "enabled"] }
		];
	for (var i = 0; i < settings.length; i++) {
		var setting = settings[i];

		setting.input = document.createElement("input");
		setting.input.setAttribute("type", "checkbox");
		setting.input.setAttribute("id", setting.id);
		setting.input.checked = readCookie(setting.cookie[0]) == setting.cookie[1];
		var label = document.createElement("label");
		label.setAttribute("for", setting.id);
		label.innerHTML = setting.label;
		
		var p = document.createElement("p");
		p.appendChild(setting.input);
		p.appendChild(label);
		content.appendChild(p);

		var desc = document.createElement("p");
		desc.className = "desc";
		desc.innerHTML = setting.desc;
		content.appendChild(desc);
	}

	var buttons = document.createElement("p");
	buttons.setAttribute("id", "settingsbuttons");
	
		var buttonSave = document.createElement("button");
		buttonSave.setAttribute("type", "button");
		buttonSave.innerHTML = ST.savebtn;
		buttonSave.onclick = function() { saveSettings(); div.parentBox.close(); };
		buttons.appendChild(buttonSave);

		var buttonCancel = document.createElement("button");
		buttonCancel.setAttribute("type", "button");
		buttonCancel.innerHTML = ST.cancelbtn;
		buttonCancel.onclick = function() { div.parentBox.close(); };
		buttons.appendChild(buttonCancel);
		
	content.appendChild(buttons);

	/* Resizes scrollArea and keeps the div centered */
	div.resizeAnimate = function(width, height, heightFirst, oncomplete, oniterate) {
			window.clearInterval(div.resizeAnimate.intervalId);

			div.resizeAnimate.intervalId = window.setInterval(function() {
					var widthFinished  = div.resizeAnimate.curWidth  == width;
					var heightFinished = div.resizeAnimate.curHeight == height;

					if ((heightFirst && heightFinished || !heightFirst) && !widthFinished) {
						var dw = (width-div.resizeAnimate.curWidth)/4;
						if (Math.abs(dw) < 5)
							dw = Math.min(5*Math.sign(dw), width-div.resizeAnimate.curWidth);

						div.resizeAnimate.curWidth = Math.floor(div.resizeAnimate.curWidth+dw);

						scrollArea.style.width = div.resizeAnimate.curWidth+"px";
					}
					if ((!heightFirst && widthFinished || heightFirst) && !heightFinished) {
						var dh = (height-div.resizeAnimate.curHeight)/4;	
						if (Math.abs(dh) < 5)
							dh = Math.min(5*Math.sign(dh), height-div.resizeAnimate.curHeight);

						div.resizeAnimate.curHeight = Math.floor(div.resizeAnimate.curHeight+dh);

						scrollArea.style.height = div.resizeAnimate.curHeight+"px";
					}
					
					if (widthFinished && heightFinished) {
						window.clearInterval(div.resizeAnimate.intervalId);
						// no resizing occurs here, so it's safe to return without calling ensureCentered
						if (typeof oncomplete == "function") oncomplete();
						return;
					} else if (oniterate)
						oniterate();

					div.ensureCentered();
				}, 20);
		};
	div.resizeAnimate.curWidth  = 0;
	div.resizeAnimate.curHeight = 0;

	div.ensureCentered = function() {
			div.style.left = ((getWindowWidth()-div.offsetWidth+5)/2)+"px";
			div.style.top  = ((getWindowHeight()-div.offsetHeight+5)/2)+"px";
		};
	div.ensureCentered.startMonitor = function() {
			div.ensureCentered.stopMonitor();
			div.ensureCentered.intervalId =
				window.setInterval(function() {
					div.ensureCentered();
				}, 100);
		};
	div.ensureCentered.stopMonitor = function() {
			window.clearInterval(div.ensureCentered.intervalId);
		};

	var saveSettings = function() {
			for (var i = 0; i < settings.length; i++) {
				var setting = settings[i];
				createCookie(setting.cookie[0], setting.input.checked ? setting.cookie[1] : setting.cookie[2], 365);
			}
		};
}

// initializes the 'to the top' link
function initTopLink() {
	var toplink = document.getElementById("toplink");
	toplink.onclick = function() {
			var intervalId = window.setInterval(function() {
					var scroll = getYScroll();
					if (scroll == 0)
						window.clearInterval(intervalId);
					else if (scroll < 300)
						window.scrollTo(0, scroll-Math.max(scroll/3, 2));
					else
						window.scrollTo(0, scroll-250);
				}, 20);
			return false;
		};
}


function initEgg() {
	var d = document.createElement("div");
	var st = {
			"display": "block", "width": "1px", "height": "1px",
			"position": "fixed", "top": (Math.random()*100)+"%",
			"left": (Math.random()*100)+"%",
			"background": "rgba(128,0,0,0.4)", "cursor": "crosshair"
		};
	for (s in st)
		try { d.style[s] = st[s]; }
		catch(e) { } // IE breaks on rgba()

	var a = document.createElement("a");
	a.style.display = "none";
	a.style.width = a.style.height = "1px";
	a.setAttribute("href", "?p=himom");
	a.setAttribute("rel", "nopreview");
	d.appendChild(a);

	d.onmouseover = function() { a.style.display = "block"; };
	d.onmouseout  = function() { a.style.display = "none"; };

	window.setInterval(function() {
		d.style.top =  (Math.random()*100)+"%";
		d.style.left = (Math.random()*100)+"%";
	}, 10000);

	(document.body || document.getElementsByTagName("body")[0]).appendChild(d);
}


/* Cookie functions taken from http://www.quirksmode.org/js/cookies.html */
function createCookie(name, value, days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}
function readCookie(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}
function eraseCookie(name) {
	createCookie(name, "", -1);
}

// Creates a temporary cookie to see if cookies are enabled
function testCookies() {
	var seed = Math.floor(Math.random()*51); // random number between 0 and 50
	var value = seed * Math.floor(Math.random()*2049);

	var name = "TEMP$"+seed+"$testcookie";
	// ensure the cookie we're testing doesn't actually exist already,
	// as impossibly unlikely as that is
	eraseCookie(name);

	createCookie(name, value, 365);
	var result = readCookie(name) == value;
	eraseCookie(name);

	return result;
}


function getCurrentMedia() {
	return currentMedia;
}


function getWindowWidth() {
	if (window.innerWidth) {
		return window.innerWidth;
	} else if (document.documentElement && document.documentElement.clientWidth) {
		return document.documentElement.clientWidth;
	} else {
		return document.body.clientWidth;
	}
}
function getWindowHeight() {
	if (window.innerHeight) {
		return window.innerHeight;
	} else if (document.documentElement && document.documentElement.clientHeight) {
		return document.documentElement.clientHeight;
	} else {
		return document.body.clientHeight;
	}
}
function getYScroll() {
	if (window.pageYOffset) {
		return window.pageYOffset;
	} else if (document.documentElement && document.documentElement.scrollTop) {
		return document.documentElement.scrollTop;
	} else if (document.body) {
		return document.body.scrollTop;
	}
	return 0;
}


var rxRegexMeta = /(?=[.*?+()[^$\\])/,
	classRegexCache = {};
// Determines whether an element has the specified class.
function hasClass(elem, className) {
	if (elem.className) {
		var rxClass = className in classRegexCache ? classRegexCache[className] :
			classRegexCache[className] = new RegExp('(?:^| )'+className.replace(rxRegexMeta, "\\")+'(?: |$)');
		return rxClass.test(elem.className)
	}
	return false;
}
// Returns a two-element array of an element's position ([x, y])
function getElemPos(elem) {
	var x = 0, y = 0;
	if (elem.offsetParent) {
		do {
			x += elem.offsetLeft;
			y += elem.offsetTop;
		} while (elem = elem.offsetParent);
	}
	return [x, y];
}


function preloadImage(url, onload) {
	var img = new Image();
	if (typeof onload == "function")
		img.onload = function() { onload(img); };
	img.src = imgPathPrefix+url;
}


function addLoadEvent(func) {
	if (document.addEventListener)
		document.addEventListener("DOMContentLoaded", func, false);

	if (window.onload) {
		var oldonload = window.onload;
		window.onload = function() {
				oldonload();
				func();
			};
	} else
		window.onload = func;
}


addLoadEvent(initPage);

for (var i = 0; i < preloadImages.length; i++) {
	preloadImage(preloadImages[i], null);
}