/*
DL list expander behavior

TODO:
appendClass()
removeClass()

INSTRUCTIONS:
<dl class="expander" id="<anyid>">
*/

addLoadEvent(initExpander);

// Consts
var EXPANDER_COOKIE_PREFIX = 'exp_';
var EXPANDER_COOKIE_DURATION = 7;	// Days


// Keep track of state of items (open/closed)
var EXPAND_STATE = new Object();

// Don't need to pass value, since value is gotten from global object
function saveExpandState(id) {
	var name = EXPANDER_COOKIE_PREFIX + id;
	var value = EXPAND_STATE[id];
	var date = new Date();
	date.setTime(date.getTime()+(EXPANDER_COOKIE_DURATION*24*60*60*1000));
	var expires = "; expires="+date.toGMTString();
	document.cookie = name+"="+value+expires+"; path=/";
}

// Only needs to be read when page first loads
// After that the value is held in global object and saved
function readExpandState(id) {
	var value = 0;
	var nameEQ = EXPANDER_COOKIE_PREFIX + id + "=";
	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)	{
			value = c.substring(nameEQ.length,c.length)
			break;
		}
	}
	
	// Store in global
	EXPAND_STATE[id] = value;
	
	return value;
}

// Returns true if DT itemcode of the passed DL id is expanded, false otherwise
function isExpanded(id, itemcode) {
	return (EXPAND_STATE[id] & itemcode);
}

// Returns class that should be set on the passed item
function itemClass(id, itemcode) {
	if (isExpanded(id, itemcode)) {
		return 'expand';
	} else {
		return 'collapse';
	}
}

// Set expand state to On and save it
function setExpandState(id, itemcode) {
	EXPAND_STATE[id] |= itemcode; 
	saveExpandState(id);
}

// Unset expand and save it
function unsetExpandState(id, itemcode) {
	EXPAND_STATE[id] &= ~itemcode; 
	saveExpandState(id);
}


// Searches for DL list of appropriate class (expander) and assigns classes/events
function initExpander() {
	if (!W3CDOM) {return;}

	var i, j, idnum, dd, count, class_name;
	var dls = document.getElementsByTagName('dl');
	
	// Number of tries until failure
	var count_max = 10;
	var failed = false;
	
	// Create anchor to clone for each DT - supposedly a bit quicker than creating each time?
	var anode, txtnode; 
	var anchor = document.createElement('a');
	anchor.setAttribute('href','javascript:void(0);');
	anchor.setAttribute('title','Click to expand this item');
	
	// Setp through all DIVs of class="expander-tools" and make visible
	var divs = document.getElementsByTagName('div');
	for (i=0; i<divs.length; i++) {
		if (divs[i].className == 'expander-tools') {
			divs[i].style.visibility = 'visible';
		}
	}
	
	// Step through all DLs
	for (i=0; i<dls.length; i++) {
		if (dls[i].className == 'expander') {
			readExpandState(dls[i].id);
		
			// Get all DTs within DL and step through them
			var dts = dls[i].getElementsByTagName('dt');
			for (j=0; j<dts.length; j++) {
				idnum = Math.pow(2,j);
				dts[j].id = dls[i].id+'-'+idnum;
				
				// What class should this item be... is it expanded or collapsed?
				class_name = itemClass(dls[i].id, idnum);
				
				// Need to surround contents of DT element with anchor to make accessible from keyboard!
				// But contents of DT is not always a textNode!?
				//txtnode = dts[j].firstChild.cloneNode(true);
				//alert(txtnode.nodeValue);
				
				anode = anchor.cloneNode(false);
				anode.onclick = itemToggle;
				//anode.appendChild(txtnode);
				wrapContents(dts[j],anode);
				
				// Replace firstChild(txtNode) with newly created anchor
				//dts[j].replaceChild(anode,dts[j].firstChild);

				//txtnode.parentNode.replaceChild(anode,txtnode);
				//dts[j].insertBefore(anode,txtnode); 

				// Read Cookie to determine whether section should be [expand]ed or [collapse]d - collapse by default			
				dts[j].className = class_name;
	
				// Find next DD...
				// NB: in FF if there is a CR or space between DT and DD then there will be a nextNode inbetween!
				dd = dts[j].nextSibling;
				count = 0;	// To prevent inf loop if error in source (ie. no DD!)
				while (dd.nodeName.toLowerCase() != 'dd') {
					//alert(count + ' - ' + dd.nodeName.toLowerCase());
					count++;
					if (count > count_max) {
						failed = true;
						break;
					}
					dd = dd.nextSibling;
				}
				if (failed) {
					alert('ERROR: Failed to find the corresponding DD for DT#' + j + ' in ' + dls[i].id);
				} else {
					dd.id = dls[i].id+'dd-'+idnum;
					dd.className = class_name;
				}				
			}
		}
	}
}

// Container - Container element, whose contents(elements) we want to wrap
// Wrapper - The element we want to wrap around the contents of the Container
// eg. If the Container is the DT element, and the Wrapper is an Anchor, then...
// <dt><acronym title="Value Added Tax">VAT</acronym> &amp; <acronym title="National Insurance">NI</acronym></dt>
// Becomes:
// <dt><a href=""><acronym title="Value Added Tax">VAT</acronym> &amp; <acronym title="National Insurance">NI</acronym></a></dt>
// NB: Potentially have 'duel function' arguments - pass either ID(string) or Element(object) ...? 
function wrapContents(Container,Wrapper) {
/*
	var container = document.getElementById(ContainerID);
	var wrapper = document.createElement(WrapperType);
	if (WrapperType == 'a') {
		wrapper.setAttribute('href','index.html');
	}
*/
	
	// Init
	var new_container = Container.cloneNode(false);	// Don't clone children
	var clonednode;
	
	//if (!Container) {return false;}
	
	// Step through and clone all childern of Container to wrapper
	for(var i=0; i<Container.childNodes.length; i++) {
		clonednode = Container.childNodes[i].cloneNode(true);	// true - clone all children
		
		// Add this to wrapper
		Wrapper.appendChild(clonednode);
		
		// Direct method OK if only 1 child!
		//wrapper.appendChild(container.childNodes[i]);
	}
	
	// Add wrapper to new container
	new_container.appendChild(Wrapper);
	
	// Add this wrapper to container
	//container.appendChild(wrapper);
	
	// Replace container with the new container!
	Container.parentNode.replaceChild(new_container,Container);
	
	// (or Return the Container if success?)
	return true;
}

// EVENT: Expand/Collapse the selected item, called from Anchor within DT
function itemToggle() {
	var dt = this.parentNode;
	var id_a = dt.id.split('-');
	var dd = document.getElementById(id_a[0]+'dd-'+id_a[1]);
	if (!dd) {return;}
	
	//alert(this.nextSibling.nodeName);
	
	if (dt.className == 'expand') {
		dt.className = 'collapse';
		dd.className = 'collapse';
		// Save state in cookie
		unsetExpandState(id_a[0],id_a[1]);
	} else {
		dt.className = 'expand';
		dd.className = 'expand';
		// Save state in cookie
		setExpandState(id_a[0],id_a[1]);
	}
}

// ID - ID of DL
// State - true (expand), false (collapse)
function expandAll(ID, Expand) {
	var dd, id_a, class_name, state = 0;
	if (Expand) {
		class_name = 'expand';
	} else {
		class_name = 'collapse';
	}

	// Get a handle on this DL element
	var dl = document.getElementById(ID);
	if (!dl) {
		alert('Could not find DL element with ID: ' + ID);
		return false;
	}
	
	// Find all DTs within this DL element
	var dts = dl.getElementsByTagName('dt');
	for (var i=0; i<dts.length; i++) {
		id_a = dts[i].id.split('-');

		// Grab corresponding DD
		var dd = document.getElementById(id_a[0]+'dd-'+id_a[1]);
		if (!dd) {continue;}
		
		// Sum all the element codes together to write cookie at end
		if (Expand) {state += parseInt(id_a[1]);}
		
		// Assign classes
		dts[i].className = class_name;
		dd.className = class_name;
	}
	
	// Save cookie
	EXPAND_STATE[ID] = state;
	saveExpandState(ID);
}
