/* IP map client-side interface utilities
 * Dylan Simon <dylan@dylex.net>
 */

function uint32(x) {
	return x >>> 0;
}

function ash(x, n)
{
	if (n < -32)
		return 0;
	if (n <= 0)
		return x >>> -n;
	if (n < 32)
		return x << n;
	else
		return 0;
}

function bfmap(p) {
	var n, s;
	var x = 0, y = 0, t;
	for (n = 0, s = 1; p || !(n & 1); n++, s *= 2, p >>= 2)
		switch (p & 3)
		{
			case 0: t = y; y = x; x = t; break;
			case 1: y += s; break;
			case 2: x += s; y += s; break;
			case 3: t = 2*s - y - 1; y = s - x - 1; x = t; break;
		}
	return [x, y];
}

function bfrev(x, y) {
	var p = 0;
	var s = 2, t;
	while (x >= s || y >= s)
		s <<= 2;
	while (s > 1)
	{
		s >>= 1; p <<= 2;
		if (x >= s) { 	if (y >= s) 	{ p += 2; x -= s; y -= s; }
				else 		{ p += 3; t = 2*s - x - 1; x = s - y - 1; y = t; } }
		else 	    { 	if (y >= s) 	{ p += 1; y -= s; }
				else 		{ p += 0; t = x; x = y; y = t; } }
	}
	return p;
}

function bfbox(p, s) {
	var m = s;
	var p0 = p;
	var p1 = p + (0x55555555 & m);
	var p2 = p + (0xaaaaaaaa & m);
	var p3 = p + m;

	p0 = bfmap(p0);
	p1 = bfmap(p1);
	p2 = bfmap(p2);
	p3 = bfmap(p3);
	
	return [Math.min(p0[0],p1[0],p2[0],p3[0]),
		Math.min(p0[1],p1[1],p2[1],p3[1]),
		Math.max(p0[0],p1[0],p2[0],p3[0]),
		Math.max(p0[1],p1[1],p2[1],p3[1])];
}

const ipDelim = '.';
const ipLen = 4;

function octList(v, len) {
	var i;
	var a = new Array;
	for (i = 0; i < len; i++)
	{
		a.unshift(v&255);
		v >>>= 8;
	}
	return a;
}

function listOct(l) {
	var v = 0;
	while (l.length)
	{
		if (!/^\d+$/.test(l[0]) || l[0] >= 256)
			return;
		v <<= 8;
		v |= l.shift();
	}
	return uint32(v);
}

function ipValue(ip) {
	if (!ip)
		return;
	var l = ip.split(ipDelim);
	if (!l.length || l.length > ipLen)
		return;
	while (l.length < ipLen)
		l.push(0);
	return listOct(l);
}

function valueIp(v) {
	return octList(v, ipLen).join(ipDelim);
}

function netSplit(net)
{
	var delim = '/';
	if (net.indexOf(delim) == -1)
		delim = '-';
	var im = net.split(delim);
	var ip = im[0] == '' ? 0 : ipValue(im[0]);
	var size;
	if (im.length == 1)
		size = 0;
	else if (delim == '/')
		size = im[1] == 0 ? 0xffffffff : uint32((1 << 32 - im[1]) - 1);
	else
		size = ipValue(im[1]) - ip;
	return [ip, size];
}

function elemOff(elem)
{
	var off;
	var x = 0, y = 0;
	for (off = elem; off; off = off.offsetParent)
	{
		x += off.offsetLeft + 1;
		y += off.offsetTop + 1;
	}
	return [x-1,y-1];
}

function xmlElem(elem, name)
{
	for (var e = elem.firstChild; e; e = e.nextSibling)
		if (e.nodeName == name)
			return e;
	return;
}

function xmlText(elem)
{
	var e = xmlElem(elem, "#text");
	if (!e)
		return "";
	return e.nodeValue;
}

function xmlElemText(elem, name)
{
	var e = xmlElem(elem, name);
	if (!e)
		return "";
	return xmlText(e);
}


