﻿// menuB.js -- revised to search for div.menuXXX instead of a fixed ID.
// TO DO: drop-down hover stuff (is disabled).
// global constants
//var mainMenuId = "navigation";  // Must contain the main menu.
//var subMenuId = "subNavigation";  // Must contain ALL sub-menus.
var menuStr = "menu"; // All menu classNames must start with this.
var pageStr = "page"; // All page classNames must start with this.
var currentPageStr = "thisPage"; // li.currentPage dynamically set.
var doHoverMe = true; // NO-ACCESSIBILITY false; // IE<7 should override.
var hoverMenuStr = "menu"; // Identifies a multi-level menu.
var hoverClass = "hoverme";
var r = /hoverme\s*/;

window.onload = doit; // Attach to window's onload. <===

// Our main function, called when window is loaded.
function doit()
{
  //amIAlive();  return;  // DEBUG
  if (!document.getElementById)
    return; // Ancient javascript -- forget it.
  initmenus(menuStr);
  //dump(); // Uncomment for test output. // DEBUG
}

// menus are div.menuXXX's.
function initmenus(menuStr)
{
  var divTags = document.getElementsByTagName("div");
  //writeln("divTags: " + divTags.length);  writeln(tagsContent(divTags));  return;
  var menuTags = findTagsByClassPrefix(divTags , menuStr);
  writeln("menuTags: " + menuTags + ", " + menuTags.length);  writeln(tagsContent(menuTags));  //return;
  //var hoverMenu = initHover(mainMenuTag); // FIRST, so detect whether hovering.
  //for (var menuTag in menuTags)
  for (var i = 0; i < menuTags.length; i++)
  {
    var menuTag = menuTags[i];
    markMenuForThisPage(menuTag);
  }
}

// Return null if not found.
function getAttribute(element, attributeName)
{
  var attributes = element.attributes;
  writeln("attributes.length: " + attributes.length);
  for (var i = 0; i < attributes.length; i++)
  {
    var attr = attributes[i];
    writeln("attr-name: " + attr.nodeName + ", type: " + attr.nodeType);
    if (attr.nodeName == attributeName)
      return attr;
  }
  return null;
}

function markMenuForThisPage(menuTag)
{
  var tagClass = menuTag.className;
  writeln("markMenuForThisPage entered: " + tagClass);
  // pageName is now on <title>.
  //var rootTag = document.documentElement;
  // pageName is now on <title>.
  var titleTags = document.getElementsByTagName("title");
  var rootTag = titleTags[0];	// Suppose there is no title tag?
  writeln("rootTag.id: " + rootTag.id);
  // Find pageName.
  var pageName = extractPageName(rootTag.id, pageStr);
  if (pageName == "")
    return; // No pageName.
  writeln("pageName: " + pageName);
  //return; // TEST.

  // List both main- and sub- items.
  var liTags = menuTag.getElementsByTagName("li");
  
  // Find matching menu element(s).
  // NOTE: element is now allowed to appear more than once;
  // for example, in a two-row menu, both as a section head and
  // as the main page of the current section.
  //var itemTag = findTagByClass(liTags, pageName);
  var itemTags = findTagsByClass(liTags, pageName);
  //if (itemTag != null)
  for (var i = 0; i < itemTags.length; i++)
  {
    var itemTag = itemTags[i];
   // Mark this item by appending a special class.
    itemTag.className = itemTag.className + " " + currentPageStr;
    writeln("itemTag.className: " + itemTag.className);
    
    //var mainName = markMainMenuForThisPage(mainMenuTag, itemTag, pageName);
    //if (subMenuTag)
    //  hideOtherSubmenus(subMenuTag, mainName);  // if null, will hide ALL sub-menus.
    //// Allow sub-menus to be in same container as main-menu.
    //if (!hoverMenu) // only hide if not doing drop-down.
    //  hideOtherSubmenus(mainMenuTag, mainName);
  }
}

// className might be a series of classes separated by spaces.
// the class starting with "menu" is the one we want.
// CAUTION: "menu" could be in the middle of a name.
// RETURNS "" if not found.
function extractPageName(className, pageStr)
{
  writeln("extractPageName entered: " + className + ", " + pageStr);
  if (className == null)
    return "";
  if (className == "")
    return className;

  // Search for "menu".  But make sure isn't in middle of a name.
  var iPageStr = className.indexOf(pageStr);
  if (iPageStr < 0)
    return "";
    // EXCEPT at the start, check if previous char is a blank.
  if (iPageStr != 0)
  {
    var previousChar = className.charAt(iPageStr - 1);
    if (previousChar == " ")
    {
      // GOOD, that's what we want.
    }
    else
    {
      // Find another "menu".  THIS time we can include the initial " ".
      iPageStr = className.indexOf(" " + pageStr, iPageStr);
      if (iPageStr < 0)
        return "";
      // Remove the initial " ".
      iPageStr = iPageStr + 1;
    }
  }
  
  // Chop any preceding chars.
  if (iPageStr > 0)
    className = className.substring(iPageStr);
  
  // NOTE: "className" has been trimmed to start with the menu item.
  // Check for any following blank, which would terminate the menu name.
  var iBlank = className.indexOf(" ");
  if (iBlank > -1)
  {
    className = className.substring(0, iBlank);
  }
  
  writeln("extractPageName exited: " + className);
  return className;
}

var currentHover = null;

function setHoverMe(tag)
{
  // Clear any old hover.
  if (currentHover)
    clearHoverMe(currentHover);
    
  //amIAlive();
  c=tag.className;
  tag.className=(c? hoverClass+' '+c: hoverClass);
  tag.getElementsByTagName("ul")[0].style.visibility = "visible";
  currentHover = tag;
}

function clearHoverMe(tag)
{
  c=tag.className;
  tag.className=(c? c.replace(r,''): '');
  tag.getElementsByTagName("ul")[0].style.visibility = "hidden";
  if (currentHover == tag)
    currentHover = null;
}

function initHover(mainMenuTag)
{
  var hoverMenu = findHoverMenu(mainMenuTag);
  // CAUTION: if rename mainMenu to match drop-down's menu,
  // then need some way to know whether sub-menu's are drop-down.
  if (hoverMenu && doHoverMe)
  {
    var liTags = mainMenuTag.getElementsByTagName("li");
    for (var i = 0; i < liTags.length; i++)
    {
      var tag = liTags[i];
      // Only do to top-level li's.
      var ulTag = tag.parentNode;
      var maybeMainTag = ulTag.parentNode;
      if (maybeMainTag==hoverMenu)
      {
        var c = tag.className;
        var newClass = (c ?  c+' '+hoverClass :  hoverClass);
        // prepend class "hoverme", and make sub-menu visible.
        // TBD: If multi-level, is the child <ul> always first??
        tag.onmouseover=function(){ setHoverMe(this); };
        tag.onmouseout=function(){ clearHoverMe(this); };
        
        // (drop-down menu only.)
        // ACCESSIBILITY: catch focus on main <a> link w/i this <li>.
        // CAUTION: author might have omitted <a> link, in which case
        // the sub-menu cannot be reached via keyboard tabbing.
        var childNodes = tag.childNodes;
        var aTag = findTagByTag(childNodes, "a");
        if (aTag)
        {
          aTag.onfocus=function(){ setHoverMe(this.parentNode); };
          //NO, hides when tab to submenu item aTag.onblur=function(){ clearHoverMe(this.parentNode); };
        }
      }
    }

    // Hide submenus (non-main <ul>s).
    var ulTags = mainMenuTag.getElementsByTagName("ul");
    for (var i = 0; i < ulTags.length; i++)
    {
      var ulTag= ulTags[i];
      var parentTag = ulTag.parentNode;
      if (parentTag!=hoverMenu) // TBD: I'd like to check that it isn't an <li>.
      {
        ulTag.style.position="absolute"; // Stop occupying layout space.
        ulTag.style.visibility="hidden";
      }
    }
  }
  return hoverMenu;
}

function findHoverMenu(mainMenuTag)
{
  var divTags = mainMenuTag.getElementsByTagName("div");
  // multi-level identified with div "menu" rather than "mainMenu".
  for (var i = 0; i < divTags.length; i++)
  {
    var tag = divTags[i];
    var tagClass = tag.className;
    if (!tagClass)
      continue;
    if (tagClass == hoverMenuStr)
    {
      return tag;
    }
  }
  return null;
}

// Each sub-menu has <ul class="menuX">,
// where "menuX" is the mainMenuName of the sub-menu.
// CAUTION: mainMenuName==null to hide ALL sub-menus.
function hideOtherSubmenus(menuTag, mainMenuName)
{
  // Find all ul's w/i the navigation structure.
  // A ul with no class is left untouched -- assumed to be main menu.
  var ulTags = menuTag.getElementsByTagName("ul");
  for (var i = 0; i < ulTags.length; i++)
  {
    var tag = ulTags[i];
    var tagClass = tag.className;
    if (!tagClass)
      continue;
    if (tagClass == mainMenuName)
    {
      // Current sub-menu. Leave it visible.
    }
    else
    { // Other sub-menu. Hide it.
      tag.style.display = "none";
    }
  }
}

// IF "pageName" is a sub-menu name; e.g. "menu1-1",
// THEN locate and mark the corresponding main-menu element.
// RETURN mainMenuName if it is a submenu name, else return null.
// TBD: Suppose we can't locate the corresponding main menu?
// FOR NOW: return name anyway; maybe there is still other work for client to do.
function markMainMenuForThisPage(menuTag, itemTag, pageName)
{
  // Better approach is to check <ul>'s class.
  // For a sub-menu, that has the mainMenuName.
  var ulTag = itemTag.parentNode;
  var mainMenuName = ulTag.className;
  if (!mainMenuName)
    return null;
  
  // TBD: main menu might be under a different menuTag.
  var liTags = menuTag.getElementsByTagName("li");
  var itemTag = findTagByClass(liTags, mainMenuName);
  if (itemTag != null)
  {
   // Mark this item by appending a special class.
    itemTag.className = itemTag.className + " " + currentPageStr;
  }
  
  return mainMenuName;
}

function findTagByTag(tags, tagNameWant)
{
  if (tags && (tags.length >= 1))
  {
    var tag = tags[0];
    for (var i = 0; i < tags.length; i++)
    {
      var tag = tags[i];
      var tagNameActual = tag.nodeName.toLowerCase();
      if (tagNameActual == tagNameWant)
        return tag;
    }
  }
  return null;
}

// RETURNS list of all tags whose class starts with classPrefix.
// E.g. "menu" finds "menu", "menu123", "menuabc", etc.
// If none found, return an empty array.
// VERSION: If multiple classnames, must be the first one.
// That is, will find "menu123 foobar" but not "foobar menu123".
// NOTE: If want to search beyond first, must check whether preceded by blank,
// then keep searching if it isn't!
function findTagsByClassPrefix(tags, classPrefix)
{
  var foundTags = new Array();
  for (var i = 0; i < tags.length; i++)
  {
    var tag = tags[i];
    var tagClass = tag.className;
    writeln("tagClass: " + tagClass);
    if (tagClass)
    {
      var preIndex = tagClass.indexOf(classPrefix);
      if (preIndex==0)
      {
        writeln("found tagClass: " + tagClass);
        foundTags.push(tag);
      }
    }
  }
  return foundTags;
}

// Find ALL tags with a given class name.
// RETURNS a (possibly-empty) list of tags.
function findTagsByClass(tags, className)
{
  var foundTags = new Array();
  for (var i = 0; i < tags.length; i++)
  {
    var tag = tags[i];
    if (tag.className == className)
      foundTags.push(tag);
  }
  return foundTags;
}

// Find the FIRST tag with a given class name.
function findTagByClass(tags, className)
{
  for (var i = 0; i < tags.length; i++)
  {
    var tag = tags[i];
    if (tag.className == className)
      return tag;
  }
  return null;
}

// TBD: I couldn't get "mainLiTags.concat(subLiTags)" to work,
// so wrote my own concat.
// CAUTION: Might be modifying array1 --
// I don't know if javascript is call-by-value or by-reference.
function myconcat(array1, array2)
{
  var iResult = 0;
  var result = new Array(array1.length + array2.length);
  for (iSrc = 0; iSrc < array1.length; iSrc++)
  {
    result[iResult++] = array1[iSrc];
  }
  for (iSrc = 0; iSrc < array2.length; iSrc++)
  {
    //array1.put(array2[i]);
    result[iResult++] = array2[iSrc];
  }
  return result;
}


// ==================== TEST CODE ====================
// DEBUG
var output = "";
// DEBUG
function amIAlive()
{
  writeln("Hello");
  dump();  
}
// DEBUG
function dump()
{
  document.write(output);
}
// DEBUG
function writeln(msg)
{
  output = output + msg + "<br />";
}

function tagsContent(tags)
{
  var result = "";
  for (var i = 0; i < tags.length; i++)
  {
    var tag = tags[i];
    result = result + tag.innerHTML + "<br /><br />"
  }
  return result;
}

function testextract()
{
  var passed = true;
  passed = testextract1("", "") && passed;
  passed = testextract1("whatever", "") && passed;
  passed = testextract1("whatmenu", "") && passed;
  passed = testextract1("menuabc", "menuabc") && passed;
  passed = testextract1("menu123", "menu123") && passed;
  passed = testextract1("menuabc whatever", "menuabc") && passed;
  passed = testextract1("menuabc ", "menuabc") && passed;
  passed = testextract1("whatever menuabc", "menuabc") && passed;
  passed = testextract1("whatmenu menuabc", "menuabc") && passed;
  passed = testextract1("wmenumenu menuabc", "menuabc") && passed;
  passed = testextract1("whatever menuabc more", "menuabc") && passed;
  passed = testextract1("menuabc menu123", "menuabc") && passed;
  passed = testextract1("menu123 menuabc", "menu123") && passed;
  writeln(passFailString(passed) + "testextract()");
  return passed;
}

function testextract1(className, expectedResult)
{
  var result = extractPageName(className, pageStr);
  var passed = (result == expectedResult);
  writeln(". " + passFailString(passed) + "testextract1(" + className + ", " + expectedResult+ ") => " + result);
  //writeln(". " + passFailString(passed) + "testextract1(" + className + ", " + result);
  return passed;  
}

function testmyconcat()
{
  writeln("Hello#2");
  var passed = true;
  var array1 = new Array(1);
  array1[0] = "1-1";
  var array2 = new Array(2);
  array2[0] = "2-1";
  array2[1] = "2-2";
  var array3 = new Array(3);
  array3[0] = "1-1";
  array3[1] = "2-1";
  array3[2] = "2-2";
  //writeln("array1: " + array1);
  //writeln("array2: " + array2);
  //writeln("array3: " + array3);
  
  passed = testmyconcat1(array1, array2, array3) && passed;
  
  writeln(passFailString(passed) + "testmyconcat()");
  return passed;
}

function testmyconcat1(array1, array2, expectedResult)
{
  var result = myconcat(array1, array2);
  //var passed = (result == expectedResult);
  var passed = arraysEqual(result, expectedResult);
  writeln(". " + passFailString(passed) + "testmyconcat1(" + array1 + ";&nbsp; " + array2 + " => " + expectedResult+ ") => " + result);
  return passed;  
}

function passFailString(passed)
{
  if (passed)
    return "PASS: ";
  return "***FAIL***: ";
}

// "==" didn't work for arrays.
function arraysEqual(array1, array2)
{
  var len = array1.length;
  //writeln("lens " + len + ", " + array2.length);
  if (len != array2.length)
    return false;
  for (i = 0; i < len; i++)
  {
    //writeln( "1: " + array1[i] + ", 2: " + array2[i] + " => " + (array1[i] == array2[i]));
    if (array1[i] != array2[i])
      return false;
  }
  return true;
}

