/*
 * common.js
 *
 *
 * Common JavaScript file used by every page on the website.
 *
 *
 * Written by Arimah
 * http://arimah.beoch.net/
 *
 *
 * Do not use without permission.
 */

var $A;

(function() {

$A = function(id) { return document.getElementById(id); };
$A.create = function(elem, attrs) {
	elem = document.createElement(elem);
	if (attrs) {
		for (var k in attrs) if (attrs.hasOwnProperty(k)) {
			if (k in elem || k.substr(0, 2) == "on")
				elem[k] = attrs[k];
			else
				elem.setAttribute(k, attrs[k]);
		}
	}
	return elem;
};
$A.text = function(text) { return document.createTextNode(text); };

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 init() {
	$A.body = document.body || document.bodyElement || document.getElementsByTagName("body")[0];

	var mediaDeterminer = $A("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 or print!

	for (var i = 0; i < preloadImages.length; i++)
		$A.preload(preloadImages[i]);

	var elems = document.getElementsByTagName("*"); // yes, yes, yes, I know, I know
	var len = elems.length;
	for (i = 0; i < len; i++) {
		var elem = elems[i];
		if (!elem || elem.nodeType != 1) continue;
		if ($A.hasClass(elem, "node") && $A.hasClass(elem, "unlabeled"))
			initNode(elem);
	}

	initNav();
	initXnav();
	initSettings();
	initTopLink();

	initEgg();
}

// 'node' is a <div> or <span>
function initNode(node) {
	var anchor     = node.getElementsByTagName("a")[0];
	var image      = null;
	var label      = null;
	var fullLabel  = "";
	var fromTitle  = false;

	var spans = node.getElementsByTagName("span");
	var len = spans.length;
	for (var i = 0; i < len; i++) {
		var s = spans[i];
		if ($A.hasClass(s, "image"))
			image = s;
		else if ($A.hasClass(s, "label"))
			label = s;
		if (image && label)
			break;
	}
	if (!image || !label) return;

	var labelShown = $A.create("span", {className: "labelshown"});
	var labelNode = $A.text("");
	labelShown.appendChild(labelNode);
	label.parentNode.insertBefore(labelShown, label);

	if (fullLabel = anchor.getAttribute("title"))
		fromTitle = true;
	else
		fullLabel = label.innerHTML;

	var animIntervalId = null;
	var i = 1;
	image.onmouseover = function() {
		labelShown.style.display = "inline";
		labelNode.nodeValue = fullLabel.substr(0, 1);
		animIntervalId = window.setInterval(function() {
			if (i < fullLabel.length) {
				labelNode.nodeValue = fullLabel.substr(0, i);
				if (!fromTitle)
					label.innerHTML = fullLabel.substr(i, fullLabel.length-i);
				i++;
			} else {
				labelNode.nodeValue = fullLabel;
				if (!fromTitle)
					label.innerHTML = "";
				window.clearInterval(animIntervalId);
			}
		}, 25);
	};
	image.onmouseout = function() {
		labelShown.style.display = "none";
		labelNode.nodeValue = "";
		if (!fromTitle)
			label.innerHTML = fullLabel;
		window.clearInterval(animIntervalId);
		i = 1;
	};
}
// initializes #nav, which becomes floating when it has to
function initNav() {
	if ($A.readCookie("menustyle") == "fixed") return;

	var nav = $A("nav");
	if (!nav)
		return;

	var navStyle   = nav.style;
	var navHeight  = nav.offsetHeight;
	var topDefault = 80;  // style.css: #nav { top: 80px; }

	var frame = $A("frame");

	var current = topDefault, i = 0;
	window.setInterval(function() {
		var scroll = $A.getYScroll();
		var windowHeight = $A.getWindowHeight();

		var threshold;
		if (windowHeight < navHeight+topDefault+10)
			threshold = Math.max(windowHeight-navHeight-10, 10);
		else
			threshold = topDefault;

		var target = Math.ensureInRange(threshold,
			frame.offsetHeight-navHeight-10, scroll+10);

		if (current != target) {
			if (current+navHeight < scroll)
				current = scroll - navHeight;
			else if (current > scroll+windowHeight)
				current = scroll+windowHeight;

			var dy = (target - current)/5;
			if (Math.abs(dy) < 1)
				dy = Math.sign(dy);
			else if (Math.abs(dy) > 24)
				dy = 24*Math.sign(dy);

			current += Math.floor(dy);
			navStyle.top = current+"px";
		}
	}, 25);
}
// initializes #xnav, if there is one
function initXnav() {
	var xntoggle = $A("xntoggle");
	if (!xntoggle)
		return;

	var xnwrapper = $A("xnwrapper");
	var xnwidth   = xnwrapper.offsetWidth;
	var xnstyle   = xnwrapper.style;

	var ease = function(t) {
		var ts = t*t, tc = ts*t;
		return 6*ts*tc - 15*ts*ts + 10*tc;
	};

	var dx = 0, // 1 = hide; -1 = show
		t = 0;
	var animId = null;

	var animate = function() {
		t += dx;
		xnstyle.marginRight = (-xnwidth*ease(t/12))+"px";

		if (t == 12 || t == 0) {  // show
			if (dx > 0) xnstyle.display = "none";
			window.clearInterval(animId);
			return;
		}
	};
	var toggleTopics = function(forcedValue) {
		window.clearInterval(animId);

		if (!forcedValue)
			dx = -dx;
		else
			dx = forcedValue;

		if (dx < 0) xnstyle.display = "block";
		animId = window.setInterval(animate, 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 = initSettingsBox();

	var settingsnode = $A("settingsnode");
	var anchor = settingsnode.getElementsByTagName("a")[0];
	anchor.onclick = function() {
		box.show();
		return false;
	};
}
function initSettingsBox() {
	var box = {
		state: 0 // 0 = closed; 1 = toggling; 2 = open
	};

	var setOpacity = function(elem, value, max) {
		value = Math.ensureInRange(0, max, value);
		elem.style.opacity = value/100;
		try { elem.filters.alpha.opacity = value; }
		catch(e) {}
	};

	var overlay, ostyle, overlayOpacity, div;

	var fadeIntervalId;
	box.show = function() {
		if (box.state != 0) // closed
			return;

		// create DOM
		overlay = $A.create("div", {
			id: "lboverlay",
			onclick: function() { box.close(); }
		});
		ostyle = overlay.style;
		$A.body.appendChild(overlay); // don't forget to insert into document!

		div = initSettingsDiv(box); // actual settings box
		$A.body.appendChild(div.elem);

		div.elem.scrollIntoView();

		// fade in
		box.state = 1; // toggling
		ostyle.display = "block";
		ostyle.filter = "alpha(opacity=0)";
		overlayOpacity = 0;
		setOpacity(overlay, 0, 80);

		div.style.display = "block";
		div.resize(Math.min(500, $A.getWindowWidth()-50),
			Math.min(div.content.offsetHeight, $A.getWindowHeight()-50),
			false,
			function() {
				div.content.parentNode.style.overflow = "auto";
				div.center.startAuto();
			}
		);
		fadeIntervalId = window.setInterval(function() {
			setOpacity(overlay, overlayOpacity+=10, 80);
			if (overlayOpacity == 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
		div.center.stopAuto();
		div.content.parentNode.style.overflow = "hidden";
		div.resize(0, 0, true, function() {
			div.style.display = "none";
			$A.body.removeChild(div.elem);
		});
		fadeIntervalId = window.setInterval(function() {
			setOpacity(overlay, overlayOpacity-=10, 80);
			if (overlayOpacity == 0) {
				window.clearInterval(fadeIntervalId);
				destroyDOM();
				box.state = 0; // closed
			}
		}, 20);
	};
	function destroyDOM() {
		if (box.state == 0) // closed - no DOM exists for box
			return;

		ostyle.display = "none";
		$A.body.removeChild(overlay);
	}

	return box;
}
function initSettingsDiv(box) {
	var div = $A.create("div", {id: "settings"});
	var cookiesEnabled = $A.testCookies();

	div.appendChild($A.create("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++)
		div.appendChild($A.create("div", {className: decorClasses[i]}));

	var scrollArea = $A.create("div", {id: "sbscrollarea"});
	div.appendChild(scrollArea);

	var content = $A.create("div", {id: "sbcontent"});
	scrollArea.appendChild(content);
	content.appendChild($A.create("h2")).innerHTML = ST.settings_title;

	var note = $A.create("p", {className: "note"});
	note.innerHTML = ST.settings_top;
	content.appendChild(note);

	if (!cookiesEnabled) {
		var warning = $A.create("div", {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 = $A.create("input", {
			type: "checkbox",
			id: setting.id,
			checked: $A.readCookie(setting.cookie[0]) == setting.cookie[1]
		});
		var label = $A.create("label", {"for": setting.id});
		label.innerHTML = setting.label;
		
		var p = $A.create("p");
		p.appendChild(setting.input);
		p.appendChild(label);
		content.appendChild(p);

		var desc = $A.create("p", {className: "desc"});
		desc.innerHTML = setting.desc;
		content.appendChild(desc);
	}

	var buttons = $A.create("p", {id: "settingsbuttons"});

	var save = $A.create("button", {
		type: "button",
		onclick: function() { saveSettings(); box.close(); }
	});
	save.innerHTML = ST.savebtn;
	buttons.appendChild(save);

	var cancel = $A.create("button", {
		type: "button",
		onclick: function() { box.close(); }
	});
	cancel.innerHTML = ST.cancelbtn;
	buttons.appendChild(cancel);

	content.appendChild(buttons);

	/* Resizes scrollArea and keeps the div centered */
	var curWidth = 0, curHeight = 0;
	function resize(width, height, heightFirst, oncomplete, oniterate) {
		window.clearInterval(resize.intervalId);

		resize.intervalId = window.setInterval(function() {
			var widthFinished  = curWidth  == width;
			var heightFinished = curHeight == height;

			if ((heightFirst && heightFinished || !heightFirst) && !widthFinished) {
				var dw = (width - curWidth)/4;
				if (Math.abs(dw) < 5)
					dw = Math.min(5*Math.sign(dw), width - curWidth);

				curWidth = Math.floor(curWidth + dw);

				scrollArea.style.width = curWidth+"px";
			}
			if ((!heightFirst && widthFinished || heightFirst) && !heightFinished) {
				var dh = (height - curHeight)/4;	
				if (Math.abs(dh) < 5)
					dh = Math.min(5*Math.sign(dh), height - curHeight);

				curHeight = Math.floor(curHeight + dh);

				scrollArea.style.height = curHeight+"px";
			}
			
			if (widthFinished && heightFinished) {
				window.clearInterval(resize.intervalId);
				// no resizing occurs here, so it's safe to return without calling center
				if (oncomplete) oncomplete();
			} else {
				center();
				if (oniterate) oniterate();
			}
		}, 20);
	};

	function center() {
		div.style.left = (($A.getWindowWidth() - div.offsetWidth + 5)/2)+"px";
		div.style.top  = (($A.getWindowHeight() - div.offsetHeight + 5)/2)+"px";
	}
	center.startAuto = function() {
		center.stopAuto();
		center.intervalId = window.setInterval(center, 100);
	};
	center.stopAuto = function() {
		window.clearInterval(center.intervalId);
	};

	function saveSettings() {
		for (var i = 0; i < settings.length; i++) {
			var setting = settings[i];
			$A.writeCookie(setting.cookie[0], setting.input.checked ? setting.cookie[1] : setting.cookie[2], 365);
		}
	};

	return {
		elem: div,
		style: div.style,
		content: content,
		resize: resize,
		center: center
	};
}

// initializes the 'to the top' link
function initTopLink() {
	var toplink = $A("toplink");
	toplink.onclick = function() {
		var intervalId = window.setInterval(function() {
			var scroll = $A.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() {
	if(!{}.__defineGetter__)return;
	String.prototype.__defineGetter__("u",function(){
	return unescape(this)});var q="%72%65",r="%65%66",g="%6F%70",J=
	"%6F%6E",m="%63%6B",W="%6E%6F",T="%6F%73",D="%72%6F",x="%64%69",K=[9,4,
	-5,7,0],_,$,$$,H,B;var d=document[_='c'+(q+"%61%74%65%45%6C%65%6D%65%6E%74").u](
	x.u+'v'),a=document[_]("%25%36%31".u.u);d[_="%73%74%79%6C%65".u][
	($="%77%69%64%74%68").u]=a[_][$.u]=d[_][($$=$.replace(/(%)([0-9]{2})/g,
	function(x,a,b,c){return a+(b-K[c/3].toString())})).u+'t']=a[_][($$+"%74").u]=
	Math.floor(K.reduce(function(p,c){return p+c},0)/15)+("%"+($=70)+"%"+($+=8)).u;d[_]['p'+(T+"%69%74%69"+J).
	u]=([,$$=66,$$+=3,$,$$-=4,--$$].join("%")).u;d[_]['t'+g.u]=(Math.random()*100)+'%';d[_][("%6C"+r).u+'t']=
	(Math.random()*100)+'%';d[_][("%62%61"+m).u+'g'+(D+"%75%6E%64").u]="%72%67%62%61%28%31%32%38%2C".
	u+[0,0,0].join(',')+"%2E%34%29".u;d[_]["%63%75%72%73%6F%72".u]='c'+(D+"%73%73%68%61%69%72").u;
	a[_][$=(x+"%73%70%6C%61%79").u]=(B=([,"2","C","F"].join("%6")+m).u,H=(W+W.replace('F','5')).u);
	a[q.u+'l']=(W+"%70"+q+"%76%69%65%77").u;d[K="%61%70%70%65%6E%64%43%68%69%6C%64".u](a);
	d[((m=J+"%6D%6F%75%73%65")+"%6F%76%65%72").u]=function(){a['h'+q.u+'f']=("%2F"+g.substr(3,3)+"%2F%68%69%6D%6F%6D").u;
	a[_][$]=B};d[(m+"%6F%75%74").u]=function(){a[_][$]=H};window.setInterval(function(){d[_]['t'+g.u]=
	(Math.random()*100)+'%';d[_][("%6C"+r).u+'t']=(Math.random()*100)+'%'},10000);document["%62%6F%64%79".u][K](d);
}


/* Cookie functions taken from http://www.quirksmode.org/js/cookies.html */
$A.writeCookie = function(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=/";
};
$A.readCookie = function(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;
};
$A.deleteCookie = function(name) {
	$A.writeCookie(name, "", -1);
};
// Creates a temporary cookie to see if cookies are enabled
$A.testCookies = function() {
	var seed = Math.floor(Math.random()*5001); // random number between 0 and 5000
	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
	$A.deleteCookie(name);

	$A.writeCookie(name, value, 365);
	var result = $A.readCookie(name) == value;
	$A.deleteCookie(name);

	return result;
};

$A.getCurrentMedia = function() { return currentMedia; };

$A.getWindowWidth = function() {
	if (window.innerWidth) {
		return window.innerWidth;
	} else if (document.documentElement && document.documentElement.clientWidth) {
		return document.documentElement.clientWidth;
	} else {
		return document.body.clientWidth;
	}
};
$A.getWindowHeight = function () {
	if (window.innerHeight) {
		return window.innerHeight;
	} else if (document.documentElement && document.documentElement.clientHeight) {
		return document.documentElement.clientHeight;
	} else {
		return document.body.clientHeight;
	}
};
$A.getYScroll = function() {
	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.
$A.hasClass = function(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])
$A.getElemPos = function(elem) {
	var x = 0, y = 0;
	if (elem.offsetParent) {
		do {
			x += elem.offsetLeft;
			y += elem.offsetTop;
		} while (elem = elem.offsetParent);
	}
	return [x, y];
};

var loadingImages = [];
$A.preload = function(url, onload) {
	var img = new Image();
	img.onload = function() {
		var i = loadingImages.length;
		while (i--)
			if (loadingImages[i] == img) {
				loadingImages.splice(i, 1);
				break;
			}
		if (onload)
			onload(img);
	};
	loadingImages.push(img);
	img.src = imgPathPrefix+url;
};

$A.ajax = function(options) {
	var req = new XMLHttpRequest();
	req.open(options.method, options.url);

	var data = null;
	if (typeof options.data != "undefined") {
		if (typeof options.data == "string")
			data = options.data; // no escaping if data is string!
		else if (options.data instanceof Array) {
			var params = new Array(options.data.length);
			for (var i = 0; i < options.data.length; i++)
				params[i] = encodeURIComponent(options.data[i]);
			data = params.join("&");
		} else if (typeof options.data == "object") {
			var params = [];
			for (var k in options.data)
				if (!options.data.hasOwnProperty || options.data.hasOwnProperty(k))
				params.push(encodeURIComponent(k)+"="+encodeURIComponent(options.data[k]));
			data = params.join("&");
		} else
			data = "";
		req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		req.setRequestHeader("Content-Length", data.length);
		req.setRequestHeader("Connection", "close");
	}

	if (typeof options.onreadystatechange == "function" ||
		typeof options.oncomplete == "function") { // readyState == 4
		req.onreadystatechange = function() {
			if (options.onreadystatechange)
				options.onreadystatechange(req);

			if (req.readyState == 4 && options.oncomplete)
				options.oncomplete(req);
		};
	}

	req.send(data);
	return req;
};

if (typeof XMLHttpRequest == "undefined")
	XMLHttpRequest = function() {
		try { return new ActiveXObject("Msxml2.XMLHTTP.6.0") } catch(e) {}
		try { return new ActiveXObject("Msxml2.XMLHTTP.3.0") } catch(e) {}
		try { return new ActiveXObject("Msxml2.XMLHTTP") } catch(e) {}
		try { return new ActiveXObject("Microsoft.XMLHTTP") } catch(e) {}
	};

var onloads = [], windowOnload = function() {
	for (var i = 0; i < onloads.length; i++)
		onloads[i]();
};
$A.onload = function(func) {
	var wrapper = function() {
		if (!wrapper.hasRun) {
			func();
			wrapper.hasRun = true;
		}
	};
	if (document.addEventListener)
		document.addEventListener("DOMContentLoaded", wrapper, false);
	if (window.addEventListener)
		window.addEventListener("load", wrapper, false);
	else {
		if (window.onload !== windowOnload)
			window.onload = windowOnload;
		onloads.push(func);
	}
};

$A.onload(init);

})();