
//----- display debugging messages

function msgSet(s) {
	var div = document.getElementById('debug');
	div.innerHTML = s;
}
function msg(s) {
	var div = document.getElementById('debug');
	div.innerHTML += '<br />'+s;
}


//----- banner effects

function bannerSparkle() {
	var b = bannerObj;
	shuffle(b.indices);
	b.currIndex = -1;
	b.interval = window.setInterval(fadeInStep, 100);
}
function delayedBannerLaunch() {
	window.setTimeout(bannerSparkle, 700);
}
function fadeInStep() {
	var b = bannerObj;
	for (var i = 0; i < 15; i++) {
		b.currIndex += 1;
		if (b.currIndex == b.indices.length) {
			window.clearInterval(b.interval);
			return;
		}
		var p = b.pixelCoords[b.indices[b.currIndex]];
		var c = p%100, r = (p-c)/100;
		var cell = b.logoGrid.rows[r].cells[c];
		cell.style.opacity = cell.style.filter = '';
		cell.className = 'on';
	}
}
function sliceLaunch() {
	var s = sliceObj;
	if (!s) {
		s = sliceObj = new Object();
		s.rowNum = b.logoGrid.rows.length;
		s.colNum = b.logoGrid.rows[0].cells.length;
		s.stepSize = 10;
	}
	s.currRow = -1;
	s.direction = 0;
	s.interval = window.setInterval(sliceStep, 100);
}
function sliceStep() {
	var s = sliceObj;
	var b = bannerObj;
	if (s.direction == 0) {
		if (++(s.currRow) == s.rowNum) {
			window.clearInterval(s.interval);
			delayedBannerLaunch();
			return;
		}
		s.direction = 1-2*Math.floor(2*Math.random());
		if (s.direction < 0)
			s.currCol = s.colNum-1;
		else
			s.currCol = 0;
	}
	if (s.direction < 0) {
		if (s.currCol-s.stepSize < 0) {
			s.direction = 0;
		}
		var colLimit = s.currCol-s.stepSize;
		var cells = b.logoGrid.rows[s.currRow].cells;
		var c;
		for (c = 0; c <= colLimit; c++)
			cells[c].className = cells[c+s.stepSize].className;
		for (c = colLimit < 0 ? 0 : colLimit+1; c <= s.currCol; c++)
			cells[c].className = '';
		s.currCol -= s.stepSize;
	}
	else {
		if (s.currCol+s.stepSize >= s.colNum) {
			s.direction = 0;
		}
		var colLimit = s.currCol+s.stepSize;
		var cells = b.logoGrid.rows[s.currRow].cells;
		var c;
		for (c = s.colNum-1; colLimit <= c; c--)
			cells[c].className = cells[c-s.stepSize].className;
		c = s.colNum <= colLimit ? s.colNum-1 : colLimit-1;
		for (; s.currCol <= c; c--)
			cells[c].className = '';
		s.currCol += s.stepSize;
	}
}
function floatLaunch() {
	var p = floatObj;
	if (!p) {
		p = floatObj = new Object();
		p.charSegments = 
			[[0,5],[6,7],[8,10],[11,14],[15,18],[19,22],[23,24],
			 [27,30],[31,34],[35,38],[39,42],[43,44],[45,48]];
		p.charNum = p.charSegments.length;
		p.charIndices = new Array();
		for (var i = p.charNum-1; i >= 0; i--)
			p.charIndices[i] = i;
		p.charHeight = new Array();
	}
	for (var i = p.charNum-1; i >= 0; i--)
		p.charHeight[i] = 4;
	shuffle(p.charIndices);
	p.currIndex = -1;
	p.tick = 0;
	p.interval = window.setInterval(floatStep, 100);
}
function floatStep() {
	var p = floatObj;
	if (--(p.tick) <= 0) {
		if (p.currIndex < p.charNum-1)
			(p.currIndex)++;
		p.tick = 2+Math.floor(Math.random(2));
	}
	var segments = p.charSegments;
	for (var i = p.currIndex; i >= 0; i--) {
		var ix = p.charIndices[i];
		var height = p.charHeight[ix];
		if (height == 0) {
			if (i == p.charNum-1) {
				window.clearInterval(p.interval);
				delayedBannerLaunch();
			}
			return;
		}
		p.charHeight[ix] = --height;
		var b = bannerObj;
		var c0 = segments[ix][0];
		var c1 = segments[ix][1];
		for (var r = 0; r < height; r++) {
			for (var c = c0; c < c1; c++)
				b.logoGrid.rows[r].cells[c].className = 
					b.logoGrid.rows[r+1].cells[c].className;
		}
		for (var c = c0; c < c1; c++)
			b.logoGrid.rows[height].cells[c].className = '';
	}
}
function dissolveLaunch() {
	var d = dissolveObj;
	var b = bannerObj;
	if (!d) {
		d = dissolveObj = new Object();
		d.subLen = b.indices.length;
		d.phaseNum = 10;
		d.len = d.phaseNum*d.subLen;
		d.decrement = Math.floor(100/d.phaseNum);
		d.indices = new Array(d.len);
		for (var i = 0; i < d.len; i++)
			d.indices[i] = b.indices[i%d.subLen];
		d.percentages = new Array(d.subLen);
	}
	for (var i = 0; i < d.subLen; i++)
		d.percentages[i] = 100;
	shuffle(d.indices);
	d.interval = window.setInterval(dissolveStep, 100);
	d.currIndex = -1;
}
function dissolveStep() {
	var d = dissolveObj;
	for (var i = 0; i < 20; i++) {
		if (++d.currIndex == d.len) {
			window.clearInterval(d.interval);
			delayedBannerLaunch();
			return;
		}
		var ix = d.indices[d.currIndex];
		var p = bannerObj.pixelCoords[ix];
		var c = p%100, r = (p-c)/100;
		var percentage = d.percentages[ix]-d.decrement;
		d.percentages[ix] = percentage;
		var cell = b.logoGrid.rows[r].cells[c];
		cell.style.opacity = percentage/100.0;
		cell.style.filter = 'alpha(opacity='+percentage+')';
	}
}
function overPixels(event) {
	bannerObj.logoGrid.className = 'highlight';
	document.body.style.cursor = 'pointer';
}
function downPixels(event) {
	var event = event || window.event;
	event.cancelBubble = true;
	if (event.stopPropagation)
		event.stopPropagation();
	var b = bannerObj;
	b.logoMenu.style.left = (event.clientX-8)+'px';
	//b.logoMenu.style.display = 'inline';
	b.logoMenu.className = 'show';
}
function outPixels(event) {
	var b = bannerObj;
	if (!b.logoMenu) {
		document.body.style.cursor = 'default';
		b.logoGrid.className = '';
		return;
	}
	document.body.style.cursor = 'auto';
	if (b.logoMenu.className != 'show')
		b.logoGrid.className = '';
}
function overActionItem(event) {
	document.body.style.cursor = 'pointer';
	this.className = 'highlight';
}
function outActionItem(event) {
	this.className = '';
	document.body.style.cursor = 'default';
}
function downActionItem(event) {
	var event = event || window.event;
	event.cancelBubble = true;
	if (event.stopPropagation)
		event.stopPropagation();
	this.className = '';
	window.setTimeout(hideActions, 100);
	eval(this.id+'()');
}
function hideActions() {
	var b = bannerObj;
	document.body.style.cursor = 'auto';
	b.logoGrid.className = ''; //b.logoMenu.style.display = 'none';
	b.logoMenu.className = '';
}
function bannerOutsideClick(event) {
	hideActions();
}
function shuffle(arr) {
	var a, b, t, len = arr.length;
	for (var i = 2*len; i >= 0; i--) {
		a = Math.floor(len*Math.random());
		b = Math.floor(len*Math.random());
		t = arr[a];
		arr[a] = arr[b];
		arr[b] = t;
	}
}

function extractDomain(uri) {
	var pos = uri.indexOf('://');
	if (pos != -1)
		uri = uri.substring(pos+3);
	pos = uri.indexOf('/');
	if (pos != -1)
		uri = uri.substring(0, pos);
	return uri;
}

var bannerObj;
var floatObj;
var sliceObj;
var dissolveObj;

function bannerPrep() {
	b = bannerObj = new Object();
	var logoGrid = b.logoGrid = document.getElementById('logoGrid');
	logoGrid.className = '';
	var pixelCoords = b.pixelCoords = new Array();
	var indices = b.indices = new Array();
	var rowNum = 4, colNum = 48;
	for (var i = 0; i < rowNum; i++) {
		for (var j = 0; j < colNum; j++) {
			var cell = logoGrid.rows[i].cells[j];
			if (classIncludes(cell, 'x')) {
				pixelCoords.push(100*i+j);
				indices.push(indices.length);
			}
		}
	}

	logoGrid.onmouseover = overPixels;
	logoGrid.onmouseout = outPixels;

	if (window.location.pathname != '/') {
		for (var i = pixelCoords.length-1; i >= 0; --i) {
			var p = pixelCoords[i], c = p%100, r = (p-c)/100;
			logoGrid.rows[r].cells[c].className = 'on';
		}
		logoGrid.onmousedown = function() {
			// the following is required because Firefox and Opera preserve
			//   DOM state in the page history
			outPixels();

			window.location.assign('/');
		};
		return;
	}

	logoGrid.onmousedown = downPixels;
	if (document.onmousedown) {
		var action = document.onmousedown;
		document.onmousedown = function(){ action(); bannerOutsideClick(); };
	}
	else
		document.onmousedown = bannerOutsideClick;

	var logoMenu = b.logoMenu = document.getElementById('logoMenu');
	var items = logoMenu.getElementsByTagName('td');
	for (var i = items.length-1; i >= 0; i--) {
		items[i].onmouseover = overActionItem;
		items[i].onmouseout = outActionItem;
		items[i].onmousedown = downActionItem;
	}
	bannerSparkle();
}


//----- attempt to foil email-address scrapers

function defudge(s) {
	var ret = '', n = s.length;
	for (var i = 0; i < n; i+=2) {
		if (i+1 < n)
			ret += s.charAt(i+1);
		ret += s.charAt(i);
	}
	return ret;
}
function crypticPrep() {
	var span = document.getElementById('crypticSpan');
	if (!span)
		return;
	var s = 'a<h er=fm"iatl:oehll@oimhceallsalz.ooc"mh>leolm@ciahlealzsolc.mo/<>a';
	span.innerHTML = defudge(s);
}


//----- class utilities; I should fold these into a library, shouldn't I?

function classIncludes(element, seekName) {
	var names = element.className.split(' ');
	for (var i = 0; i < names.length; i++)
		if (names[i] == seekName)
			return true;
	return false;
}

function classAdd(element, plusName) {
	if (classIncludes(element, plusName))
		return;
	if (element.className == '')
		element.className = plusName;
	else
		element.className += ' '+plusName;
}

function classRemove(element, minusName) {
	var oldNames = element.className.split(' ');
	var newNames = [];
	for (var i = 0; i < oldNames.length; i++) {
		var name = oldNames[i];
		if (name == '' || name == minusName)
			continue;
		newNames.push(name);
	}
	element.className = newNames.join(' ');
}

function getElementsByClassName(candidates, seekName) {
	var found = [];
	for (var i = 0; i < candidates.length; i++) {
		var candidate = candidates[i];
		if (classIncludes(candidate, seekName))
			found.push(candidate);
	}
	return found;
}


//----- prepare flyouts, which contain hidden text that appears on demand

function flyoutPrep() {
	var divs = document.getElementsByTagName('div');
	var flyouts = getElementsByClassName(divs, 'flyout');
	for (var i = 0; i < flyouts.length; i++) {
		var flyout = flyouts[i];
		var divs = flyout.getElementsByTagName('div');
		var tab = getElementsByClassName(divs, 'tab')[0];
		var text = getElementsByClassName(divs, 'text')[0];
		tab.text = text;
		tab.onmouseover = overFlyout;
		tab.onmouseout = outFlyout;
		tab.onmousedown = downFlyout;
	}
}

function overFlyout() {
	document.body.style.cursor = 'pointer';
	classAdd(this, 'hover');
}
function outFlyout() {
	document.body.style.cursor = 'default';
	classRemove(this, 'hover');
}
function downFlyout() {
	var tab = this;
	var text = tab.text;
	if (!classIncludes(text, 'show')) {
		classAdd(text, 'show');
		classAdd(tab, 'hide');
		tab.innerHTML = '&laquo; hide examples';
	}
	else {
		classRemove(text, 'show');
		classRemove(tab, 'hide');
		tab.innerHTML = 'show examples &raquo;';
	}
}


//----- dynamically adjust height of navigation column

function resize() {
	var viewportHeight = Math.max(document.body.clientHeight,
			document.documentElement.clientHeight);
	var contentHeight = document.getElementById('content').scrollHeight;
	var navigation = document.getElementById('navigation');
	navigation.style.height = Math.max(viewportHeight, contentHeight)+'px';
}


//----- actions to take after the HTML has loaded

function mlPrep() {
	resize();
	window.onresize = resize;
	crypticPrep();
	bannerPrep();
	flyoutPrep();
}


//   In addition to preserving state (which is addressed above by outPixels),
//   Firefox 3.6.20 seems to do buggy stuff after clicking Back, notably
//   turning on text selection. We can get around this by disabling the
//   bfcache, as follows.
window.onunload = function() {
	msg('window.onselect');
};

if (window.onload) {
	var action = window.onload;
	window.onload = function(){ mlPrep(); action(); };
}
else
	window.onload = mlPrep;


