// INSTRUCTIONS: this WON'T WORK unless you do the following in the document that includes it:
//
// 1. In the <head> element of your page, bring in this code:
//
//    <script src="resizing_background.js">
//    </script>
//
// 2. Call outlineInit() from your onLoad handler:
//
//    <body onLoad="outlineInit()">
//
//    If you need other code in onLoad, that's fine. Just separate the calls with semicolons ( ; ).
//
// 3. To create your outline, write a nested list with the <ul>... <li>...</li>...  </ul> elements as you normally would.
//    Make sure the TOP <ul> element is a member of the outline class.
//    DO NOT assign the outline class to any nested <ul> elements beneath.
//
//    THIS IS THE RIGHT WAY:
//
//    <ul class="outline">
//      <li>Item One
//        <ul> <!-- This ul does NOT get class="outline" -->
//          <li>Subitem One</li>
//        </ul> 
//      </li>
//      Et cetera...
//    </ul>
//


var openPNG_URL;
var closePNG_URL;

function setIconDir(dirBase) {
	openPNG_URL = dirBase + "/oopen.png";
	closePNG_URL = dirBase + "/oclose.png";
}


var outlineItems = new Array();

function outlineInit() {
	var elements = outlineGetTopLevelLists();
	for (var i = 0; (i < elements.length); i++) {
		outlineInitOutline(elements[i]);
	}		
}

function outlineInitOutline(outline) {
	var kids = outline.childNodes;
	for (var i = 0; (i < kids.length); i++) {
		var kid = kids[i];
		if (kid.nodeName == "LI") {
			outlineInitItem(kid);
		}
	}
}


function outlineInitItem(item) {
	var kids = item.childNodes;
	var hasKids = false;
	var outlines = new Array();
	for (var i = 0; (i < kids.length); i++) {
		var kid = kids[i];	
		if (kid.nodeName == "UL") {
			kid.style.display = "none";
			outlineInitOutline(kid);
			hasKids = true;
			outlines[outlines.length] = kid;
		}
	}
	
	
	// We can't just modify item.innerHTML, because that would invalidate JavaScript objects that already refer to
	// other elements in the outlineItems array. So we use the clunky DOM way of creating a span element. Then we
	// tuck the "a" element inside it so we can use innerHTML for that and avoid various IE bugs.
	if (hasKids) {
		item.style.cursor = "pointer";
		var len = outlineItems.length;
		outlineItems[len] = item;
		var span = document.createElement("span");
		span.innerHTML = "<a href='#' onClick='outlineItemClickByOffset(" + len + "); return false' class='olink'><img class='oimg' alt='Open' src='" + openPNG_URL + "'></a>";
		item.insertBefore(span, kids[0]);
		item.onclick = outlineItemClick;
	}
}


function outlineGetTarget(evt) {
	var target;
    if (!evt) {
        evt = window.event; // Old IE
    }
    
	// Prevent double event firing (sigh)
	evt.cancelBubble = true;
	if (evt.stopPropagation) {
		evt.stopPropagation();
	}
	
    target = evt.target;
    if (!target) {
         target = evt.srcElement; // Old IE
    }
	return target;
}


function outlineItemClickByOffset(id) {
	outlineItemClickBody(outlineItems[id]);
}

function outlineItemClick(evt) {
	var target = outlineGetTarget(evt);
	outlineItemClickBody(target);
}


function outlineItemClickBody(target) {
	var closed = true;
	var kids = target.childNodes;
	var hasKids = false;
	for (var i = 0; (i < kids.length); i++) {
		var kid = kids[i];	
		if (kid.nodeName == "UL") {
			if (kid.style.display == "none") {
				kid.style.display = "block";
			} else {	
				kid.style.display = "none";
				closed = false;
			}
			hasKids = true;
		}
	}
	if (!hasKids) {
		// We're here because of a click on a childless node. Ignore that.
		return;
	}	
	var img = outlineGetImg(target);
	if (closed) {
		// We've just opened it, show close button
		img.src = closePNG_URL;
		img.alt = "Close";
	} else {
		img.src = openPNG_URL;
		img.alt = "Open";
	}
}
	
function outlineGetImg(target) {
	return outlineGetDescendantWithClassName(target, "oimg");
}


// Regular expression: beginning with class name, or class name preceded by a space; and ending with class name, or
// class name followed by a space. Covers the ways a single class name can appear with or without others in the className attribute.
function outlineGetDescendantWithClassName(parent, cn) {
	var elements = parent.childNodes;
	var length = elements.length;
	var i;
	var regexp = new RegExp("(^| )" + cn + "( |$)");
	for (i = 0; (i < length); i++) {
		if (regexp.test(elements[i].className)) {
			return elements[i];
		}
		var result = outlineGetDescendantWithClassName(elements[i], cn);	
		if (result) {
			return result;
		}
	}
	return null;
}



// Regular expression: beginning with class name, or class name preceded by a space; and ending with class name, or
// class name followed by a space. Covers the ways a single class name can appear with or without others in the className attribute.
function outlineGetTopLevelLists() {
	var cn = "outline";
	var elements = document.getElementsByTagName("ul");
	var length = elements.length;
	var i;
	var regexp = new RegExp("(^| )" + cn + "( |$)");
	var results = new Array();
	for (i = 0; (i < length); i++) {
		if (regexp.test(elements[i].className)) {
			results.push(elements[i]);
		}
	}
	return results;
}
