/*
 * Collapsible Menu
 * (c) 11 July, 2005. Eden Adogla
 * ------------------------------------------------------------------
 * A relatively robust collapsible menu script requiring little 
 * configuration in the HTML code. Basically runs away with concept
 * of separation of content from functionality. All styling done in 
 * CSS. Work in progress.
 * ------------------------------------------------------------------
 * 
 *
 * Modifications TODO:
 * ------------------------------------------------------------------
 */

/**
 * Function: updateMenu
 * Syntax:   updateMenu(menuID);
 * ------------------------------------------------------------------
 * Sets the menu style of a <DT> element when it is clicked on. 
 * It sets the state by altering the css class of the <A> element in
 * within the <DT> parentNode in question setting it to 'expanded', 
 * 'collapsed' or 'childless'.
 * This convoluted approach is used not because I love convolution
 * but because it is a simple way to ensure blocked-hover effects for
 * all the menu items even in IE.
 *
 * Alternative is using the .htc/behaviour approach which insidiously
 * yet ingeniously inserts javascript via css
 * [http://www.xs4all.nl/~peterned/csshover.html] 
 * We will play with that one of these days.
 * ------------------------------------------------------------------
 */
 
function updateMenu (menuID) {
  var menu = document.getElementById(menuID);
  if(menu == null) return;
  var menuItem = getMenuItems(menu.parentNode);
  if(menuItem == null) {
    /*therefore menu is childless*/
	menu.className = 'childless';
  } else {
	var menuState	= menuItem.className;
	if (menuState != "expanded-menu") {
	  menuItem.className = "expanded-menu";
	  menu.className	 = "expanded";
	  createCookie(menuID, "expanded");
	} else {
	  menuItem.className = "collapsed-menu";
	  menu.className	 = "collapsed";
	  createCookie(menuID, "collapsed");
	}
  }
}
/**
 * Function: isChildless
 * Syntax:   isChildless();
 * ------------------------------------------------------------------
 * Returns true if menu has no submenus; false otherwise
 * ------------------------------------------------------------------
 */
function isChildless (menu) {
  return (getMenuItems(menu) == null);
}

/**
 * Function: resetMenu
 * Syntax:   resetMenu();
 * ------------------------------------------------------------------
 * Called on onLoad() to reset the menu to its previous state
 * ------------------------------------------------------------------
 */
function resetMenu () {
  if (document.getElementById) {
	var menuNode	= document.getElementById("collapsible-menu");
	var menusList	= document.getElementsByTagName("dt");
    for (var i=0; i<menusList.length; i++) {
      var menu		= menusList[i];
	  var parent	= menu.parentNode;
	  var myAnchor  = getMenuAnchor(menu);
	  if(myAnchor != null) {
	    var menuID	= myAnchor.id;
		if(parent.className == "collapsible-menu") {
		  var menuItem	= getMenuItems(menu);
		  if(menuItem ==null) {
		    /*therefore menu is childless*/
			myAnchor = getMenuAnchor(menu);
			if(myAnchor != null) myAnchor.className = 'childless';  
		  } else {
			var state 	= readCookie(menuID);
			myAnchor = getMenuAnchor(menu);
			if(state != null)	{
			  menuItem.className	= state + "-menu";
			  if(myAnchor != null) myAnchor.className = state;  
			}else{
			  menuItem.className  = "collapsed-menu";
			  if(myAnchor != null) myAnchor.className = 'collapsed';  
			}
			/* attach onClick functionality to the <DD> level menu */
			//myAnchor.addEventListener("click", updateMenu, false);
			myAnchor.setAttribute('href', "javascript:updateMenu('"+myAnchor.id+"');");
		  }
		}
	  }
    }
  }
}

/**
 * Function: getMenuAnchor
 * Syntax:   var myAnchor = getMenuAnchor(menu);
 * ------------------------------------------------------------------
 * Returns the first and hopefully only <A> anchor within given menu
 * A menu anchor has the ID by which the menu is referred. If must 
 * have an ID for this menu to work
 * For now, the menu is expected to be a <DT> element.
 * ------------------------------------------------------------------
 */
 function getMenuAnchor(menuDT) {
  if(menuDT == null) return null;
  var child = null;
  child = menuDT.firstChild;
  while(true) {			
    if(child == null) break;
	if(child.tagName == 'A') break;		 
	child = child.nextSibling;
  }
  return child;
}

/**
 * Function: getMenuItems
 * Syntax:   var menuItems = getMenuItems(menuDT);
 * ------------------------------------------------------------------
 * Returns the next <DD> element when passed in a DT element.
 * For simplicity sake, the DT element is expected to follow directly 
 * after the <DD> element with the possibility of only one intercepting 
 * non-<DD> sibling. Beyond that we abort and return null
 * ------------------------------------------------------------------
 */
function getMenuItems(menu){
  if(!menu) return null;
  if(menu.tagName != 'DT') return null;
  var sibling = menu.nextSibling;
  if(sibling == null) return null;
  var tagName = sibling.tagName;
  if(tagName == 'DT') return null;
  if(tagName == 'DD') {
	return sibling;
  } else {
	sibling = sibling.nextSibling;
	if((sibling != null) && (sibling.tagName == 'DD')) {
	  return sibling;
	}
  }
  return null;
}

/**
 * Function: createCookie
 * Syntax:   createCookie(name, value);
 * ------------------------------------------------------------------
 * Creates a persistent cookie with the name-value parameters given
 * ------------------------------------------------------------------
 */
function createCookie(name,value) {
  days = 1000;
  if (days) {
    var date = new Date();
    date.setTime(date.getTime()+(days*24*60*60*1000));
    var expiryString = "; expires="+date.toGMTString();
  }
  else expiryString = "";
  document.cookie = name+"="+value+expiryString+"; path=/";
}

/**
 * Function: readCookie
 * Syntax:   readCookie(name);
 * ------------------------------------------------------------------
 * Returns the value associated to the named parameter if it exists;
 * null otherwise
 * ------------------------------------------------------------------
 */
function readCookie(name) {
  var nameEQ = name + "=";
  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) return c.substring(nameEQ.length,c.length);
  }
  return null;
}

/**
 * Function: InitialiseMenu
 * ------------------------------------------------------------------
 * All basic initialisations will occur here. 
 * ------------------------------------------------------------------
 */
function InitialiseMenu(){
  resetMenu();
  //TODO: assign event triggers to elements dynamically
  //TODO: open current page's menu	
}

