//***********************************************
//* Slashdot Menu script- By DimX
//* Submitted to Dynamic Drive DHTML code library: http://www.dynamicdrive.com
//* Visit Dynamic Drive at http://www.dynamicdrive.com/ for full source code
//***********************************************

//***********************************************
//* May 2007: Modified by Ictinus for nested submenus and wrapping menu items.
//***********************************************
//* Note: rarely but reproducably a submenu can appear to be too long for the links 
//* within it, a slight reduction in width will usually make a link wrap to fill up the space.
//* The browser just isn't calculating the height correctly.
//***********************************************

// Remember menu states, and restore them on next visit.
var remember = true;

// defaultStates - An array of zeros and ones (0,1,1,0) that represent open (0) and closed (1) menus.
// if the array is empty, no default state of menu will be loaded. if the array has values, but not as 
// many as there are menus, you will be alerted.
//var defaultStates = new Array(1,1,1,1,0,0,1);
var defaultStates = new Array();

// Should all submenus be contracted by default? (true or false)
var contractall_default = false;

// NOTE: order or priority for menu states is 'remember' (ie. use cookie), 
// defaultStates (if array not empty), 'contractall_default'

// Basically it's speed, but if the (number of submenu elements * bypixels) is larger than 
// the submenu height the menu will change height by ~50% each step.
var bypixels = 2;

// if true, close the last menu that was opened if it was not a parent or child menu.
var collapse_lastmenu = true;

// if true, collapse top level menus only; requires collapse_lastmenu to be true.
var collapse_topmenus_only = false;

// if you want the menus to open instantly
var bInstantMenus = true;

//milliseconds to menu redraw incase of window or font resize.
var redraw_timeout = 30;

// if true, the submenus will be refreshed if needed at the redraw_timeout interval.
// this allows the menu to work with font and window resizing.
var bRefreshMenu = true;

// number of pixels for submenu menu title indents.
var iSubmenuIndent = 0;
// number of pixels for submenu item indent level.
var iSubmenuItemIndent = 0;

//====== should be no need to configure anything below this line, but feel free to be adventurous ======//
var menu, titles, titletext, submenus, bypixels;
var submenu_haschildren = new Array();
var menuWidth = 0;
var menuHeight = 0;
var lastMenu = 0;
var refreshdelay;
var q = new Array();
var qOpen;
var qClose;
var submenuState = new Array();

/**
 *
 */
function forceRedraw() {
   if ((q[0] == false) && (q[1] == false)) { 
      if (((menuWidth != menu.offsetWidth) || (menuHeight != menu.offsetHeight))) {
         restoreFromCookie();
      }
   }
}

/**
 *
 */
function refreshmenu() {
   if (q[0] == true) {
      (bInstantMenus) ? hidemenunow(qClose, true) : hidemenu(qClose, true);
   }
   if (q[1] == true) {
      (bInstantMenus) ? showmenunow(qOpen, true, true) : showmenu(qOpen, true);
   }
   // only redraw the menu if we aren't closing or opening a submenu
   if ((q[0] == false) && (q[1] == false)) {
      // and only do it if the menu dimensions have changed
      if (((menuWidth != menu.offsetWidth) || (menuHeight != menu.offsetHeight))) { 
         if (bRefreshMenu) {
            restoreFromMemory();
         }
      }
   }
}

/**
 *
 */
function slash_expandall(bStore){
   if (typeof menu!="undefined"){
      for (var i=submenus.length-1; i >= 0; i--){
         if (submenu_haschildren[i] == true)
            showmenunow(i, bStore, false);
      }
   }
}

/**
 *
 */
function slash_contractall(bStore){
   if (typeof menu!="undefined"){
      for (var i=0; i<submenus.length; i++){
         hidemenunow(i, bStore);
      }
   }
}

/**
 *
 */
function initmenu(){
   var sublvls;

   menu = getElementsByClassName("sdmenu", "div", document)[0];
   titles = getElementsByClassName("title", "span", menu);
   submenus = getElementsByClassName("submenu", "div", menu);
   titletext = getElementsByClassName("tt", "span", menu);

   if ((defaultStates.length > 0) && (defaultStates.length != submenus.length)) {
      //alert('The number of default states is ' + defaultStates.length + ', but the number of menus is ' +submenus.length)
   }

   for (var i=0; i<submenus.length; i++) {
      titles[i].onclick = gomenu;
      titletext[i].onclick = gomenu;
      submenus[i].style.height = submenuHeight(submenus[i])+"px";
      submenu_haschildren[i] = (submenus[i].getElementsByTagName("*").length > 0)
   }
   setSubmenuMargins(menu, 0);

   // set the menu to the appropriate collapse/expand state
   (remember) ? restoreFromCookie() : restoreStates(defaultStates);
   
   refreshdelay = setInterval("refreshmenu()", redraw_timeout);
   
   // set no current menu activity
   q[0] = false;
   q[1] = false; 
}

/**
 *
 */
function setSubmenuMargins(oElm, currentMargin) {
   var oElmCurrent = oElm.firstChild;
   while (oElmCurrent) {
      if (oElmCurrent.className == "submenu") {
         setSubmenuMargins(oElmCurrent, parseInt(currentMargin) + parseInt(iSubmenuIndent));
      }
      else if (oElmCurrent.nodeType == 1) {// nodeType test to skip non-HTML elements, i.e. text nodes
         if (oElmCurrent.nodeName == "A") {
            
            // submenu title link
            if ((oElmCurrent.firstChild.className == "title") || (oElmCurrent.firstChild.className == "titlehidden")) {
               oElmCurrent.firstChild.firstChild.style.marginLeft = String(currentMargin) + "px" ;
            }
            // normal menu link
            else {
               oElmCurrent.firstChild.style.marginLeft = String(parseInt(currentMargin)+(parseInt(iSubmenuItemIndent))) + "px" ;
            }
         }
         else if ((oElmCurrent.className == "title") || (oElmCurrent.className == "titlehidden")) {
            oElmCurrent.firstChild.style.marginLeft = String(currentMargin) + "px" ;
         }
      }
      oElmCurrent = oElmCurrent.nextSibling;
   }
}

/**
 *
 */
function restoreStates(arrStates) {
   if (submenus.length == arrStates.length) {
      for (var i=arrStates.length-1; i>=0; i--) {
         if (arrStates[i] == 1 || submenu_haschildren[i] == false) {
            hidemenunow(i, true);
         }
         else {
            showmenunow(i, true, false);
         }
      } 
   }
   else {
      if (submenus.length == defaultStates.length) {
         restoreStates(defaultStates);
      }
      else if (contractall_default == true) {
         slash_contractall(true);
      }
      else {
         slash_expandall(true);
      }
   }
}

/**
 *
 */
function restoreFromMemory() {
   for (var i=submenuState.length-1; i>=0; i--) {
      if (submenuState[i] == 1) {
         if (parseInt(submenus[i].style.height) != 0 || submenu_haschildren[i] == false) {
            hidemenunow(i, false); // no need to store cookie info, it will be the same in the end
         }
      }
      else {
         if (parseInt(submenus[i].style.height) != submenuHeight(submenus[i])) {
            showmenunow(i, false, false); // no need to store cookie info, it will be the same in the end
         }
      }
   }
}

/**
 *
 */
function restoreFromCookie() {
   if (getcookie("menu") != null) {
      submenuState = getcookie("menu").split(",");
      restoreStates(submenuState);
   }
   else {
      restoreStates(defaultStates);
   }
   menuWidth = menu.offsetWidth;
   menuHeight = menu.offsetHeight;
}

/**
 *
 */
function gomenu(e) {
   // if we don't allow multiple menus to be manipulated at the same time, check to see if one is being manipulated
   if ((q[0] == true || q[1] == true) && collapse_lastmenu == false) {
      return;
   }

   if (!e) var e = window.event;
   var ce = (e.target) ? e.target : e.srcElement;
   var sm;

   i = 0; sm = -1;
   while (i < titles.length && sm == -1) {
      if(titles[i] == ce || titletext[i] == ce) {
         sm = i;
      }
      i++;
   }

   // only expand the menu if it has sub elements
   // do not allow the event to bubble up to containing span
   // keep anti-bubble code within "if submenu_haschildren[sm] == true"
   if (submenu_haschildren[sm] == true) { 
   
      if (e.preventDefault) {
         e.preventDefault();
      }
      e.returnValue = false;
      if (e.stopPropagation) {
         e.stopPropagation();
      }
      e.cancelBubble = true;
      
      if (parseInt(submenus[sm].style.height) > 0) {
         qClose = sm;
         // action taken in function refreshMenus
         q[0] = true;
      }
      else if (parseInt(submenus[sm].style.height) == 0) {
         if (collapse_lastmenu == true) {
            
            // don't collapse lastmenu when it is related... menu 1/submenu 1.1/submenu 1.1.1
            if (isAncestor(submenus[sm], submenus[lastMenu]) != true) {
               if (isAncestor(submenus[lastMenu], submenus[sm]) != true) {
                  qClose = lastMenu;
                  q[0] = true; // action taken in function refreshMenus
               }
            }
         }
         qOpen = sm;
         // action taken in function refreshMenus
         q[1] = true;
      }
   }
}

/**
 *
 */
function isAncestor(oElm, oElmTest) {
   if (oElm.className != 'sdmenu') {
      if (oElm == oElmTest) {
         return (true);
      }
      else {
         return (isAncestor(oElm.parentNode, oElmTest));
      }
   }
   else {
      return (false);
   }   
}

/**
 * Recursively expand child submenus (that are not hidden) of the given menu element
 * I don't believe this should be needed, but without it the auto-resize/restore function 
 * prevented submenus from being drawn as menus expand.
 */
function expandChildren(oElm) {
   var oElmCurrent = oElm.firstChild;

   while (oElmCurrent) {
      if (oElmCurrent.className == "submenu") {
         if (oElmCurrent.style.display != "none") {
            oElmCurrent.style.height = submenuHeight(oElmCurrent)+"px"; 
            expandChildren(oElmCurrent);
         }
      }   
      oElmCurrent = oElmCurrent.nextSibling;
   }
}

/**
 * Recursively change the height of the object oElm and its parent until the parent 
 * object is 'sdmenu' or the parent not displayed.
 * Note: if iDelta is negative, the menu height will be decreased, if it is positive, 
 * the menu height will increase.
 */
function changeHeight(oElm, iDelta) {
   var newHeight;

   // ensure submenus that should be displayed are displayed.
   expandChildren(oElm);
   while ((oElm.className != "sdmenu") && (oElm.style.display != "none")) {
      newHeight = parseInt(oElm.style.height) + iDelta;
      if (newHeight <= 0) {
         oElm.style.height = "0px";
      }
      else {
         oElm.style.height = newHeight+"px";
      }
      var lastElm = oElm;
      oElm = oElm.parentNode;
   }
}

/**
 *
 */
function hidemenu(sm, bStore) {
   var iDelta = submenuChildCount(submenus[sm])*bypixels;

   if (iDelta >= parseInt(submenus[sm].style.height)) {
      iDelta = Math.floor((parseInt(submenus[sm].style.height)+1)/2);
   }
   changeHeight(submenus[sm], -iDelta);

   if (parseInt(submenus[sm].style.height) == 0) {
      titles[sm].className = "titlehidden";
      titletext[sm].className = "tthidden";
      submenus[sm].style.display = "none";
      if (bStore == true) {
         store();
      }
      // must set q[0] here because this is the only time we know the hiding has finished.
      q[0] = false;
   }
}

/**
 *
 */
function hidemenunow(sm, bStore) {
   // whatever the height is, reduce the height by this much to make it 0, make the same height 
   // change to parent elements
   changeHeight(submenus[sm], - parseInt(submenus[sm].style.height));
   titles[sm].className = "titlehidden";
   titletext[sm].className = "tthidden";
   submenus[sm].style.display = "none";
   if (bStore == true) {
      //alert("storing");
      store();
   }
   // must set q[0] here because this is the only time we know hidemenu has finished.
   q[0] = false;
}


/**
 *
 */
function submenuChildCount(oElm) {
   var subMenuCC = 0;
   var oElmCurrent = oElm.firstChild;

   while (oElmCurrent) {
      if (oElmCurrent.className == "submenu") {
         if (oElmCurrent.style.display != "none") {
            subMenuCC = subMenuCC + submenuChildCount(oElmCurrent);
         }
      }
      else if (oElmCurrent.nodeType == 1) { // not submenu so add height of element...
         // nodeType test to skip non-HTML elements, i.e. text nodes
         subMenuCC = subMenuCC + 1;
      }   
      oElmCurrent = oElmCurrent.nextSibling;
   }
   return subMenuCC;
}

/**
 *
 */
function submenuHeight(oElm) {
   var th = 0;
   var oElmCurrent;

   oElmCurrent = oElm.firstChild;

   while (oElmCurrent) {
      if (oElmCurrent.className == "submenu") {
         if (oElmCurrent.style.display != "none") {
            th = th + submenuHeight(oElmCurrent);
         }
      }
      else if (oElmCurrent.nodeType == 1) { // not submenu so add height of element...
         // nodeType test to skip non-HTML elements, i.e. text nodes
         th = th + oElmCurrent.offsetHeight;
      }   
      oElmCurrent = oElmCurrent.nextSibling;
   }
   return th;
}

/**
 *
 */
function showmenu(sm, bStore, bRememberLastMenu) {
   
   var iDelta;
   var iChildCount = submenuChildCount(submenus[sm]);

   submenus[sm].style.display = "";
   titles[sm].className = "title";
   titletext[sm].className = "tt";
   var i = 0;

   var submenuContentHeight = submenuHeight(submenus[sm]);
   iDelta = iChildCount * bypixels;

   if (iDelta >= submenuContentHeight - parseInt(submenus[sm].style.height)) {
      iDelta = Math.floor((submenuContentHeight - parseInt(submenus[sm].style.height)+1)/2);
   }
   changeHeight(submenus[sm], iDelta);
   
   if (parseInt(submenus[sm].style.height) == submenuContentHeight) {
      if ((collapse_topmenus_only != true) || (submenus[sm].parentNode == menu)) {
         lastMenu = sm;
      } // remember the appropriate lastmenu
      //alert("bStore=" + bStore);
       if (bStore == true) {
          store();
       }
      // must set q[1] here because this is the only time we know showmenu has finished.
      q[1] = false;
   }
}

/**
 *
 */
function showmenunow(sm, bStore, bRememberLastMenu) {
   submenus[sm].style.display = "";
   titles[sm].className = "title";
   titletext[sm].className = "tt";

   // calculate the last iDelta, ie. the difference between the submenu div height and the submenu content height
   var iDelta = submenuHeight(submenus[sm]) - parseInt(submenus[sm].style.height);
   changeHeight(submenus[sm], iDelta);
   
   // remember the appropriate lastmenu
   if (bRememberLastMenu && ((collapse_topmenus_only != true) || (submenus[sm].parentNode == menu))) {
      lastMenu = sm;
   }
   //alert("bStore=" + bStore);
   if (bStore == true) {
      store();
   }
   
   // must set q[1] here because this is the only time we know the hiding has finished.
   q[1] = false;
}

/**
 *
 */
function store() {
   submenuState = new Array();

   for (var i=0; i<submenus.length; i++) {
      if (submenus[i].style.display == "none" || submenu_haschildren[i] == false) {
         submenuState.push(1);  // collapsed
      }
      else {
         submenuState.push(0);  // expanded
      }
   }
   //alert("setting cookie with value of " + submenuState.join(","));
   putcookie("menu", submenuState.join(","), 30);
}

/**
 *
 */
function getElementsByClassName(strClassName, strTagName, oElm){
   var arrElements = (strTagName == "*" && document.all) ? document.all : oElm.getElementsByTagName(strTagName);
   var arrReturnElements = new Array();
   strClassName = strClassName.replace(/\-/g, "\\-");
   var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$)");
   var oElement;
   for (var i=0; i<arrElements.length; i++ ){
      oElement = arrElements[i];     
      if (oRegExp.test(oElement.className)) {
         arrReturnElements.push(oElement);
      }
   }
   return (arrReturnElements)
}

/**
 * Stores menu state in a cookie.
 */
function putcookie(c_name,value,expiredays) {
   var exdate=new Date();
   exdate.setDate(exdate.getDate()+expiredays);
	Set_Cookie(c_name,value,expiredays, "/", "", "");
	Set_Cookie(c_name,value,expiredays, "/aboutus", "", "");
	Set_Cookie(c_name,value,expiredays, "/forms", "", "");
	Set_Cookie(c_name,value,expiredays, "/media", "", "");
	Set_Cookie(c_name,value,expiredays, "/media/bios", "", "");
	Set_Cookie(c_name,value,expiredays, "/pubs", "", "");
	Set_Cookie(c_name,value,expiredays, "/results", "", "");
	Set_Cookie(c_name,value,expiredays, "/services", "", "");
	Set_Cookie(c_name,value,expiredays, "/sections/corp", "", "");
	Set_Cookie(c_name,value,expiredays, "/sections/nonp", "", "");
	Set_Cookie(c_name,value,expiredays, "/sections/phil", "", "");
	//var str = c_name + "=" + escape(value) + ((expiredays==null) ? "" : ";expires=" + exdate + ";path=/");
	//alert(str);
	//document.cookie = str;
   //document.cookie = c_name + "=" + escape(value) + ((expiredays==null) ? "" : ";expires=" + exdate + ";path=/");
}

/**
 * Gets menu state from a cookie.
 */
function getcookie(c_name) {
   if (document.cookie.length > 0) {
      var c_start = document.cookie.indexOf(c_name + "=");
      if (c_start != -1) {
         c_start = c_start + c_name.length + 1;
         var c_end = document.cookie.indexOf(";",c_start);
         if (c_end == -1) {
            c_end = document.cookie.length;
         }
         return unescape(document.cookie.substring(c_start, c_end));
      }
   }
   return null;
}

function Set_Cookie(name, value, expires, path, domain, secure) {
	// set time, it's in milliseconds
	var today = new Date();
	today.setTime( today.getTime() );

	/*
	if the expires variable is set, make the correct 
	expires time, the current script below will set 
	it for x number of days, to make it for hours, 
	delete * 24, for minutes, delete * 60 * 24
	*/
if (expires) {
	expires = expires * 1000 * 60 * 60 * 24;
}
var expires_date = new Date( today.getTime() + (expires) );

document.cookie = name + "=" + escape(value) +
( (expires) ? ";expires=" + expires_date.toGMTString() : "" ) + 
( (path) ? ";path=" + path : "" ) + 
( (domain) ? ";domain=" + domain : "" ) +
( (secure) ? ";secure" : "" );
}
