function MM_findObj(n, d) { //v4.01
	var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
		d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
	if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
	for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
	if(!x && d.getElementById) x=d.getElementById(n); return x;
}
//
// Return the object of the specified name (p.first), caching the
// object reference in the specified holder (p.second).
//
// pre: p is a Pair
//      p.first is a string naming a browser object (e.g. "x" from <div id=x>)
function div(p)
{
	if (p.second == undefined)
	{
		p.second = MM_findObj(p.first);
		if (p.second == null)
		{
			alert('could not find object' + p.first);
		}
	}
	return p.second;
}
function setDivVisible(obj, value)
{
	var v = value ? 'show':'hide';
	if (obj.style) 
	{
		obj=obj.style;
		v=(v=='show')?'visible':'hidden';
	}
	obj.visibility=v;
}
function Pair(first, second)
{
	this.first = first;
	this.second = second;
}
function quo(x)
{
   return '"' + x + '"';
}
function sty(n, v)
{
   return ' '+ n + ': ' + v + ';';
}
function cloneExtent()
{
	return new Extent(this.minX, this.minY, this.maxX, this.maxY);
}
function Extent(minX, minY, maxX, maxY)
{
	this.minX = minX;
	this.minY = minY;
	this.maxX = maxX;
	this.maxY = maxY;
	this.clone = cloneExtent;
}
function extentUnion(e1, e2)
{
	var result = new Extent(Math.min(e1.minX, e2.minX),
							Math.min(e1.minY, e2.minY),
							Math.max(e1.maxX, e2.maxX),
							Math.max(e1.maxY, e2.maxY));
	return result;
}
//
// Defines a menu item that, when clicked, opens
// the specified target url.
//
// pre: name is a string
//      target is a string
//  
ItemDefaults = new Object;
ItemDefaults.height = 20;
ItemDefaults.style = 'none';

function closeItem()
{
}
function Item(text)
{
	this.id = 'none';
	this.text = text;
	this.height = ItemDefaults.height;
	this.style = ItemDefaults.style;
	this.close = closeItem;
}
function writeLeaf(id, x, y, z, width)
{
	this.id = id;
	this.localExtent = new Extent(x, y, x+width, y+this.height);
    var s = '<div id=' +quo(this.id) + 
			' class=' + quo(this.style) + 
	    	' style="' + 
		    	sty('z-index', z) + 
				sty('position', 'absolute') +
		 		sty('left', x) +
				sty('top' , y) +
				sty('width', width) +
				sty('height', this.height) +
		  	'" onmouseover="allLeaves[\''+id+'\'].show();">' +
 		'<a class=' + quo(this.style) + ' href=' + quo(this.target) + '>' +
	   	this.text +
	   	'</a>' +
		'</div>';
	this.div = new Pair(this.id, undefined);
	allLeaves[id] = this;
	document.writeln(s);
}
function leafExtent()
{
	return this.localExtent;
}
function setLeafVisible(value)
{
	setDivVisible(div(this.div), value);
}
function showLeaf()
{
	if (this.parent)
	{
		this.parent.closeOthers(this.id);
	}
}
function Leaf(text, target)
{
	this.base = Item;
	this.base(text);
	this.target = target;
	this.write = writeLeaf;
	this.extent = leafExtent;
	this.setVisible = setLeafVisible;
	this.show = showLeaf;
}
allLeaves = new Object;

//
// A "Menu" is a vertical sequence of Items, each separated
// by spacers, and having a left margin.
//
MenuDefaults = new Object;
MenuDefaults.marginWidth = 4;
MenuDefaults.spacerHeight = 2;
MenuDefaults.spacerColour = "#00ff00";
MenuDefaults.style = ItemDefaults.style;

function menuHeight()
{
	var result = 0
	for(var i = 0; i != this.items.length; ++i)
	{
		result += this.items[i].height;
	}
	if (this.items.length)
	{
		result += (this.items.length-1) * this.spacerHeight;
	}
	return result;
}
function menuExtent()
{
	var result = this.localExtent.clone();
	for(var i = 0; i != this.items.length; ++i)
	{
		result = extentUnion(result, this.items[i].extent());
	}
	return result;
}
function writeMenu(id, x, y, z, width)
{
	this.id = id;
	this.localExtent = new Extent(x, y, x+width+this.marginWidth, y+this.height());
	allMenus[id] = this;
	var s = '<div id=' +quo(this.id+'.margin') + 
		' class=' + quo(this.style) + 
    	' style="' + 
	    	sty('z-index', z) + 
			sty('position', 'absolute') +
		 	sty('left', x) +
			sty('top' , y) +
			sty('width', this.marginWidth+width) +
			sty('height', this.height()) +
			sty('font-size', 1) +
	  	'">&nbsp;</div>';
	document.writeln(s);
	this.divIds.push(new Pair(this.id+'.margin', undefined));
	var ix = x + this.marginWidth;
	var iy = y;
	for(var i = 0; i != this.items.length; ++i)
	{
		if (i != 0)	{ 
			this.writeSpacer(this.id+'.spacer.'+i, ix, iy, z, width);	
			iy+=this.spacerHeight;
		}
		this.items[i].write(this.id+'.item.'+i, ix, iy, z, width);
		iy += this.items[i].height;
	}
}
function writeMenuSpacer(id, x, y, z, width)
{
	var s = '<div' + 
		' id='+ quo(id) +
		' class=' + quo(this.style) + 
	   	' style="' + 
	    	sty('z-index', z) + 
			sty('position', 'absolute') +
	 		sty('left', x) +
			sty('top' , y) +
			sty('width', width) +
			sty('height', this.spacerHeight) +
			sty('font-size', 1) +
			sty('background', this.spacerColour) +
	  	'">&nbsp;</div>';
	document.writeln(s);
	this.divIds.push(new Pair(id, undefined));
}
function setMenuVisible(value)
{
	for(var i = 0; i != this.divIds.length; ++i)
	{
		setDivVisible(div(this.divIds[i]), value);
	}
	for(i = 0; i != this.items.length; ++i)
	{
		this.items[i].setVisible(value);
	}
}
function closeMenuOthers(except)
{
	for(var i = 0; i != this.items.length; ++i)
	{
		if (this.items[i].id != except)
		{
			this.items[i].close();
		}
	}
}
function Menu(items)
{
	this.items = items;
	this.marginWidth = MenuDefaults.marginWidth;
	this.spacerHeight = MenuDefaults.spacerHeight;
	this.spacerColour = MenuDefaults.spacerColour;
	this.write = writeMenu;
	this.height = menuHeight;
	this.style = MenuDefaults.style;
	this.writeSpacer = writeMenuSpacer;
	this.setVisible = setMenuVisible;
	this.extent = menuExtent;
	this.closeOthers = closeMenuOthers;
	this.closeAll = function()
	{
		for (var i = 0; i != this.items.length; ++i)
		{
			this.items[i].close();
		}
	}
	this.menuOpened = function()
	{
		if (this.parent)
		{
			this.parent.menuOpened();
		}
	}
	this.divIds=new Array;
	for (var i = 0; i != items.length; ++i)
	{
		items[i].parent = this;
	}
}
allMenus = new Object;

BranchDefaults = new Object;
BranchDefaults.tabWidth = 10;
BranchDefaults.tabHeight = 10;
BranchDefaults.arrowImage = 'arrow.gif';
BranchDefaults.arrowWidth = 10;
BranchDefaults.arrowTopMargin = 0;

function writeBranch(id, x, y, z, width)
{
	this.id = id;
	this.localExtent = 
		new Extent(x, y, 
				   x+width+this.tabWidth, y+Math.max(this.tabHeight, this.height));
	allBranches[id] = this;
	var s = '<div id=' +quo(this.id) + 
		' class=' + quo(this.style) + 
    	' style="' + 
	    	sty('z-index', z) + 
			sty('position', 'absolute') +
		 	sty('left', x) +
			sty('top' , y) +
			sty('width', width) +
			sty('height', this.height) +
	  	'" onmouseover="allBranches[\''+id+'\'].show();" '+
		'onclick="allBranches[\''+id+'\'].follow();">' +
		'<a class=' + quo(this.style) + ' href=' + quo(this.target) + '>' + 
		this.text + 
		'</a>' +
		'</div>';
	this.itemDiv = new Pair(this.id, undefined);
	document.writeln(s);
	s = '<div id=' +quo(this.id+'.arrow') + 
		' class=' + quo(this.style) + 
    	' style="' + 
	    	sty('z-index', z+1) + 
			sty('position', 'absolute') +
		 	sty('left', x+width-this.arrowWidth) +
			sty('top' , y+this.arrowTopMargin) +
			sty('width', this.arrowWidth) +
			sty('height', this.height - this.arrowTopMargin) +
	  	'" onmouseover="allBranches[\''+id+'\'].show();" '+
		'onclick="allBranches[\''+id+'\'].follow();">' +
		'<img border=0 src=' + quo(this.arrowImage) + '>' +
		'</div>';
	this.arrowDiv = new Pair(this.id+'.arrow', undefined);
	document.writeln(s);
	s = '<div id=' +quo(this.id+'.tab') + 
		' class=' + quo(this.style) + 
    	' style="' + 
	    	sty('z-index', z+1) + 
			sty('position', 'absolute') +
		 	sty('left', x+width) +
			sty('top' , y) +
			sty('width', this.tabWidth) +
			sty('height', this.tabHeight) +
			sty('font-size', 1) +
	  	'">&nbsp;</div>';
	document.writeln(s);
	this.tabDiv = new Pair(this.id+'.tab', undefined);
	this.menu.write(this.id+'.menu', x+width+this.tabWidth, y, z+1, this.menuWidth);
	this.setSubVisible(false);
}
function Branch(text, target, menuWidth, items)
{
	this.base = Item;
	this.base(text);
	this.target = target;
	this.menuWidth = menuWidth;
	this.menu = new Menu(items);
	this.menu.parent = this;
	this.tabWidth = BranchDefaults.tabWidth;
	this.tabHeight = BranchDefaults.tabHeight;
	this.arrowImage = BranchDefaults.arrowImage;
	this.arrowWidth = BranchDefaults.arrowWidth;
	this.arrowTopMargin = BranchDefaults.arrowTopMargin;
	
	this.write = writeBranch;
	this.extent = function()
	{
		var result = extentUnion(this.localExtent, this.menu.extent());
		return result;
	}

	this.setSubVisible = function(value)
	{
		setDivVisible(div(this.tabDiv), value);
		this.menu.setVisible(value);
	}

	this.setVisible = function(value)
	{
		this.setSubVisible(false);
		setDivVisible(div(this.itemDiv), value);		
		setDivVisible(div(this.arrowDiv), value);		
	}
	this.show = function()
	{
		if (this.parent)
		{
			this.parent.closeOthers(this.id);
		}
		this.setSubVisible(true);
		if (this.parent)
		{
			this.parent.menuOpened();
		}
	}
	this.close = function()
	{
		this.setSubVisible(false);
	}
	this.follow = function()
	{
		window.location = this.target;
	}
	this.menuOpened = function()
	{
		if (this.parent)
		{
			this.parent.menuOpened();
		}
	}
}
allBranches = new Object;

//
// Drop - a "drop down" menu, which is just like a branch but
// has no arrow and positions its sub-menu below rather than
// beside.
//
DropDefaults = new Object;
DropDefaults.offset = 0;

function writeDrop(id, x, y, z, width)
{
	this.id = id;
	this.localExtent = new Extent(x, y, x+width, y+this.height);
	allDrops[id] = this;
	var s = '<div id=' +quo(this.id) + 
		' class=' + quo(this.style) + 
    	' style="' + 
	    	sty('z-index', z) + 
			sty('position', 'absolute') +
		 	sty('left', x) +
			sty('top' , y) +
			sty('width', width) +
			sty('height', this.height) +
			'padding: 0em;' +
	  	'" onmouseover="allDrops[\''+id+'\'].show();" '+
		'onclick="allDrops[\''+id+'\'].follow();">' +
		'<a class=' + quo(this.style) + ' href=' + quo(this.target) + '>' + 
		this.text + 
		'</a>' +
		'</div>';
	this.itemDiv = new Pair(this.id, undefined);
	document.writeln(s);
	this.menu.write(this.id+'.menu', x+this.offset, y+this.height, z+1, this.menuWidth);
	this.setSubVisible(false);
}
function Drop(text, target, menuWidth, items)
{
	this.base = Item;
	this.base(text);
	this.target = target;
	this.menuWidth = menuWidth;
	this.menu = new Menu(items);
	this.menu.parent = this;
	this.offset = DropDefaults.offset;
	
	this.write = writeDrop;
	this.extent = function()
	{
		var result = extentUnion(this.localExtent, this.menu.extent());
		return result;
	}

	this.setSubVisible = function(value)
	{
		this.menu.setVisible(value);
	}

	this.setVisible = function(value)
	{
		if (!value)
		{
			this.setSubVisible(value);
		}
		setDivVisible(div(this.itemDiv), value);		
	}
	this.show = function()
	{
		if (this.parent)
		{
			this.parent.closeOthers(this.id);
		}
		this.setSubVisible(true);
		if (this.parent)
		{
			this.parent.menuOpened();
		}
	}
	this.close = function()
	{
		this.setSubVisible(false);
	}
	this.follow = function()
	{
		window.location = this.target;
	}
	this.menuOpened = function()
	{
		if (this.parent)
		{
			this.parent.menuOpened();
		}
	}
}
allDrops = new Object;

function writeTree(id, x, y, z, width)
{
	this.menu.write(id, x, y, z+1, width);
	this.backingExtent = this.menu.extent().clone();
	this.backingExtent.minX -= 2;
	this.backingExtent.minY -= 2;
	this.backingExtent.maxX += 2;
	this.backingExtent.maxY += 2;
	if (this.backingExtent.minX < 0) { this.backingExtent.minX = 0; }
	if (this.backingExtent.minY < 0) { this.backingExtent.minY = 0; }
	var s = '<div id=' +quo(this.id+'.bg') + 
		' style="' + 
	    	sty('z-index', z) + 
			sty('position', 'absolute') +
		 	sty('left', this.backingExtent.minX) +
			sty('top' , this.backingExtent.minY) +
			sty('width', this.backingExtent.maxX - this.backingExtent.minX) +
			sty('height', this.backingExtent.maxY - this.backingExtent.minY) +
			sty('visibility', 'hidden') +
		  	' background-color: white; filter: alpha(opacity=0);" ' +
			' onmouseover="allTrees[\''+this.id+'\'].closeAll();"></div>';
	document.writeln(s);
	this.bgDiv = new Pair(this.id+'.bg', undefined);
	allTrees[this.id] = this;
}
function Tree(id, x, y, z, width, items)
{
	this.id = id;
	this.menu = new Menu(items);
	this.menu.parent = this;
	this.write = writeTree;
	this.write(id, x, y, z, width);
	this.extent = function()
	{
		return this.backingExtent.clone();
	}
	this.closeAll = function()
	{
		this.menu.closeAll();
		setDivVisible(div(this.bgDiv), false);
	}
	this.menuOpened = function()
	{
		setDivVisible(div(this.bgDiv), true);
	}
}
allTrees = new Object;

