/*
  JSCookMenu v2.0.4 (c) Copyright 2002-2006 by Heng Yuan
*/

// default node properties
var _cmNodeProperties =
{
  // theme prefix
  prefix: '',

    // main menu display attributes
    //
    // Note.  When the menu bar is horizontal,
    // mainFolderLeft and mainFolderRight are
    // put in <span></span>.  When the menu
    // bar is vertical, they would be put in
    // a separate TD cell.

    // HTML code to the left of the folder item
    mainFolderLeft: '',
    // HTML code to the right of the folder item
    mainFolderRight: '',
  // HTML code to the left of the regular item
  mainItemLeft: '',
  // HTML code to the right of the regular item
  mainItemRight:  '',

  // sub menu display attributes

  // HTML code to the left of the folder item
  folderLeft:   '',
  // HTML code to the right of the folder item
  folderRight:  '',
  // HTML code to the left of the regular item
  itemLeft:   '',
  // HTML code to the right of the regular item
  itemRight:    '',
  // cell spacing for main menu
  mainSpacing:  0,
  // cell spacing for sub menus
  subSpacing:   0,

  // optional settings
  // If not set, use the default

  // auto disappear time for submenus in milli-seconds
  delay:      500,

  // 1st layer sub menu starting index
  zIndexStart:  1000,
  // z-index incremental step for subsequent layers
  zIndexInc:    5,

  // sub menu header appears before the sub menu table
  subMenuHeader:  null,
  // sub menu header appears after the sub menu table
  subMenuFooter:  null,

  // submenu location adjustments
  //
  // offsetHMainAdjust for adjusting the first submenu
  //    of a 'hbr' menu.
  // offsetVMainAdjust for adjusting the first submenu
  //    of a 'vbr' menu.
  // offsetSubAdjust for subsequent level of submenus
  //
  offsetHMainAdjust:  [0, 0],
  offsetVMainAdjust:  [0, 0],
  offsetSubAdjust:  [0, 0],

  // act on click to open sub menu
  // not yet implemented
  // 0 : use default behavior
  // 1 : hover open in all cases
  // 2 : click on main, hover on sub
  // 3 : click open in all cases (illegal as of 1.5)
  clickOpen:    1,

  // special effects on open/closing a sub menu
  effect:     null
};

// Globals
var _cmIDCount = 0;
var _cmIDName = 'cmSubMenuID';    // for creating submenu id

var _cmTimeOut = null;        // how long the menu would stay
var _cmCurrentItem = null;      // the current menu item being selected;

var _cmNoAction = new Object ();  // indicate that the item cannot be hovered.
var _cmNoClick = new Object ();   // similar to _cmNoAction but does not respond to mouseup/mousedown events
var _cmSplit = new Object ();   // indicate that the item is a menu split

var _cmMenuList = new Array ();   // a list of the current menus
var _cmItemList = new Array ();   // a simple list of items

var _cmFrameList = new Array ();  // a pool of reusable iframes
var _cmFrameListSize = 0;     // keep track of the actual size
var _cmFrameIDCount = 0;      // keep track of the frame id
var _cmFrameMasking = true;     // use the frame masking

// disable iframe masking for IE7
/*@cc_on
  @if (@_jscript_version >= 5.6)
    if (_cmFrameMasking)
    {
      var v = navigator.appVersion;
      var i = v.indexOf ("MSIE ");
      if (i >= 0)
      {
        if (parseInt (navigator.appVersion.substring (i + 5)) >= 7)
          _cmFrameMasking = false;
      }
    }
  @end
@*/

var _cmClicked = false;       // for onClick

// flag for turning on off hiding objects
//
// 0: automatic
// 1: hiding
// 2: no hiding
var _cmHideObjects = 0;

// Utility function to do a shallow copy a node property
function cmClone (nodeProperties)
{
  var returnVal = new Object ();
  for (v in nodeProperties)
    returnVal[v] = nodeProperties[v];
  return returnVal;
}

//
// store the new menu information into a structure to retrieve it later
//
function cmAllocMenu (id, menu, orient, nodeProperties, prefix)
{
  var info = new Object ();
  info.div = id;
  info.menu = menu;
  info.orient = orient;
  info.nodeProperties = nodeProperties;
  info.prefix = prefix;
  var menuID = _cmMenuList.length;
  _cmMenuList[menuID] = info;
  return menuID;
}

//
// request a frame
//
function cmAllocFrame ()
{
  if (_cmFrameListSize > 0)
    return cmGetObject (_cmFrameList[--_cmFrameListSize]);
  var frameObj = document.createElement ('iframe');
  var id = _cmFrameIDCount++;
  frameObj.id = 'cmFrame' + id;
  frameObj.frameBorder = '0';
  frameObj.style.display = 'none';
  frameObj.src = 'javascript:false';
  document.body.appendChild (frameObj);
  frameObj.style.filter = 'alpha(opacity=0)';
  frameObj.style.zIndex = 99;
  frameObj.style.position = 'absolute';
  frameObj.style.border = '0';
  frameObj.scrolling = 'no';
  return frameObj;
}

//
// make a frame resuable later
//
function cmFreeFrame (frameObj)
{
  _cmFrameList[_cmFrameListSize++] = frameObj.id;
}

//////////////////////////////////////////////////////////////////////
//
// Drawing Functions and Utility Functions
//
//////////////////////////////////////////////////////////////////////

//
// produce a new unique id
//
function cmNewID ()
{
  return _cmIDName + (++_cmIDCount);
}

//
// return the property string for the menu item
//
function cmActionItem (item, isMain, idSub, menuInfo, menuID)
{
  _cmItemList[_cmItemList.length] = item;
  var index = _cmItemList.length - 1;
  idSub = (!idSub) ? 'null' : ('\'' + idSub + '\'');

  var clickOpen = menuInfo.nodeProperties.clickOpen;
  var onClick = (clickOpen == 3) || (clickOpen == 2 && isMain);

  var param = 'this,' + isMain + ',' + idSub + ',' + menuID + ',' + index;

  var returnStr;
  if (onClick)
    returnStr = ' onmouseover="cmItemMouseOver(' + param + ',false)" onmousedown="cmItemMouseDownOpenSub (' + param + ')"';
  else
    returnStr = ' onmouseover="cmItemMouseOverOpenSub (' + param + ')" onmousedown="cmItemMouseDown (' + param + ')"';
  return returnStr + ' onmouseout="cmItemMouseOut (' + param + ')" onmouseup="cmItemMouseUp (' + param + ')"';
}

//
// this one is used by _cmNoClick to only take care of onmouseover and onmouseout
// events which are associated with menu but not actions associated with menu clicking/closing
//
function cmNoClickItem (item, isMain, idSub, menuInfo, menuID)
{
  // var index = _cmItemList.push (item) - 1;
  _cmItemList[_cmItemList.length] = item;
  var index = _cmItemList.length - 1;
  idSub = (!idSub) ? 'null' : ('\'' + idSub + '\'');

  var param = 'this,' + isMain + ',' + idSub + ',' + menuID + ',' + index;

  return ' onmouseover="cmItemMouseOver (' + param + ')" onmouseout="cmItemMouseOut (' + param + ')"';
}

function cmNoActionItem (item)
{
  return item[1];
}

function cmSplitItem (prefix, isMain, vertical)
{
  var classStr = 'cm' + prefix;
  if (isMain)
  {
    classStr += 'Main';
    if (vertical)
      classStr += 'HSplit';
    else
      classStr += 'VSplit';
  }
  else
    classStr += 'HSplit';
  return eval (classStr);
}

//
// draw the sub menu recursively
//
function cmDrawSubMenu (subMenu, prefix, id, nodeProperties, zIndexStart, menuInfo, menuID)
{
  var str = '<div class="' + prefix + 'SubMenu" id="' + id + '" style="z-index: ' + zIndexStart + ';position: absolute; top: 0px; left: 0px;">';
  if (nodeProperties.subMenuHeader)
    str += nodeProperties.subMenuHeader;

  str += '<table summary="sub menu" id="' + id + 'Table" cellspacing="' + nodeProperties.subSpacing + '" class="' + prefix + 'SubMenuTable">';

  var strSub = '';

  var item;
  var idSub;
  var hasChild;

  var i;

  var classStr;

  for (i = 5; i < subMenu.length; ++i)
  {
    item = subMenu[i];
    if (!item)
      continue;

    if (item == _cmSplit)
      item = cmSplitItem (prefix, 0, true);
    item.parentItem = subMenu;
    item.subMenuID = id;

    hasChild = (item.length > 5);
    idSub = hasChild ? cmNewID () : null;

    str += '<tr class="' + prefix + 'MenuItem"';
    if (item[0] != _cmNoClick)
      str += cmActionItem (item, 0, idSub, menuInfo, menuID);
    else
      str += cmNoClickItem (item, 0, idSub, menuInfo, menuID);
    str += '>'

    if (item[0] == _cmNoAction || item[0] == _cmNoClick)
    {
      str += cmNoActionItem (item);
      str += '</tr>';
      continue;
    }

    classStr = prefix + 'Menu';
    classStr += hasChild ? 'Folder' : 'Item';

    str += '<td class="' + classStr + 'Left">';

    if (item[0] != null)
      str += item[0];
    else
      str += hasChild ? nodeProperties.folderLeft : nodeProperties.itemLeft;

    str += '</td><td class="' + classStr + 'Text">' + item[1];

    str += '</td><td class="' + classStr + 'Right">';

    if (hasChild)
    {
      str += nodeProperties.folderRight;
      strSub += cmDrawSubMenu (item, prefix, idSub, nodeProperties, zIndexStart + nodeProperties.zIndexInc, menuInfo, menuID);
    }
    else
      str += nodeProperties.itemRight;
    str += '</td></tr>';
  }

  str += '</table>';

  if (nodeProperties.subMenuFooter)
    str += nodeProperties.subMenuFooter;
  str += '</div>' + strSub;
  return str;
}

//
// The function that builds the menu inside the specified element id.
//
// id       id of the element
// orient     orientation of the menu in [hv][ub][lr] format
// menu       the menu object to be drawn
// nodeProperties properties for the theme
// prefix     prefix of the theme
//
function cmDraw (id, menu, orient, nodeProperties, prefix)
{
  var obj = cmGetObject (id);

  if (!prefix)
    prefix = nodeProperties.prefix;
  if (!prefix)
    prefix = '';
  if (!nodeProperties)
    nodeProperties = _cmNodeProperties;
  if (!orient)
    orient = 'hbr';

  var menuID = cmAllocMenu (id, menu, orient, nodeProperties, prefix);
  var menuInfo = _cmMenuList[menuID];

  // setup potentially missing properties
  if (!nodeProperties.delay)
    nodeProperties.delay = _cmNodeProperties.delay;
  if (!nodeProperties.clickOpen)
    nodeProperties.clickOpen = _cmNodeProperties.clickOpen;
  if (!nodeProperties.zIndexStart)
    nodeProperties.zIndexStart = _cmNodeProperties.zIndexStart;
  if (!nodeProperties.zIndexInc)
    nodeProperties.zIndexInc = _cmNodeProperties.zIndexInc;
  if (!nodeProperties.offsetHMainAdjust)
    nodeProperties.offsetHMainAdjust = _cmNodeProperties.offsetHMainAdjust;
  if (!nodeProperties.offsetVMainAdjust)
    nodeProperties.offsetVMainAdjust = _cmNodeProperties.offsetVMainAdjust;
  if (!nodeProperties.offsetSubAdjust)
    nodeProperties.offsetSubAdjust = _cmNodeProperties.offsetSubAdjust;
  // save user setting on frame masking
  menuInfo.cmFrameMasking = _cmFrameMasking;

  var str = '<table summary="main menu" class="' + prefix + 'Menu" cellspacing="' + nodeProperties.mainSpacing + '">';
  var strSub = '';

  var vertical;

  // draw the main menu items
  if (orient.charAt (0) == 'h')
  {
    str += '<tr>';
    vertical = false;
  }
  else
  {
    vertical = true;
  }

  var i;
  var item;
  var idSub;
  var hasChild;

  var classStr;

  for (i = 0; i < menu.length; ++i)
  {
    item = menu[i];

    if (!item)
      continue;

    item.menu = menu;
    item.subMenuID = id;

    str += vertical ? '<tr' : '<td';
    str += ' class="' + prefix + 'MainItem"';

    hasChild = (item.length > 5);
    idSub = hasChild ? cmNewID () : null;

    str += cmActionItem (item, 1, idSub, menuInfo, menuID) + '>';

    if (item == _cmSplit)
      item = cmSplitItem (prefix, 1, vertical);

    if (item[0] == _cmNoAction || item[0] == _cmNoClick)
    {
      str += cmNoActionItem (item);
      str += vertical? '</tr>' : '</td>';
      continue;
    }

    classStr = prefix + 'Main' + (hasChild ? 'Folder' : 'Item');

    str += vertical ? '<td' : '<span';
    str += ' class="' + classStr + 'Left">';

    str += (item[0] == null) ? (hasChild ? nodeProperties.mainFolderLeft : nodeProperties.mainItemLeft)
           : item[0];
    str += vertical ? '</td>' : '</span>';

    str += vertical ? '<td' : '<span';
    str += ' class="' + classStr + 'Text">';
    str += item[1];

    str += vertical ? '</td>' : '</span>';

    str += vertical ? '<td' : '<span';
    str += ' class="' + classStr + 'Right">';

    str += hasChild ? nodeProperties.mainFolderRight : nodeProperties.mainItemRight;

    str += vertical ? '</td>' : '</span>';

    str += vertical ? '</tr>' : '</td>';

    if (hasChild)
      strSub += cmDrawSubMenu (item, prefix, idSub, nodeProperties, nodeProperties.zIndexStart, menuInfo, menuID);
  }
  if (!vertical)
    str += '</tr>';
  str += '</table>' + strSub;
  obj.innerHTML = str;
}

//
// The function builds the menu inside the specified element id.
//
// This function is similar to cmDraw except that menu is taken from HTML node
// rather a javascript tree.  This feature allows links to be scanned by search
// bots.
//
// This function basically converts HTML node to a javascript tree, and then calls
// cmDraw to draw the actual menu, replacing the hidden menu tree.
//
// Format:
//  <div id="menu">
//    <ul style="visibility: hidden">
//      <li><span>icon</span><a href="link" title="description">main menu text</a>
//        <ul>
//          <li><span>icon</span><a href="link" title="description">submenu item</a>
//          </li>
//        </ul>
//      </li>
//    </ul>
//  </div>
//
function cmDrawFromText (id, orient, nodeProperties, prefix)
{
  var domMenu = cmGetObject (id);
  var menu = null;
  for (var currentDomItem = domMenu.firstChild; currentDomItem; currentDomItem = currentDomItem.nextSibling)
  {
    if (!currentDomItem.tagName)
      continue;
    var tag = currentDomItem.tagName.toLowerCase ();
    if (tag != 'ul' && tag != 'ol')
      continue;
    menu = cmDrawFromTextSubMenu (currentDomItem);
    break;
  }
  if (menu)
    cmDraw (id, menu, orient, nodeProperties, prefix);
}

//
// a recursive function that build menu tree structure
//
function cmDrawFromTextSubMenu (domMenu)
{
  var items = new Array ();
  for (var currentDomItem = domMenu.firstChild; currentDomItem; currentDomItem = currentDomItem.nextSibling)
  {
    if (!currentDomItem.tagName || currentDomItem.tagName.toLowerCase () != 'li')
      continue;
    if (currentDomItem.firstChild == null)
    {
      items[items.length] = _cmSplit;
      continue;
    }
    var item = new Array ();
    var currentItem = currentDomItem.firstChild;
    var hasAction = false;
    for (; currentItem; currentItem = currentItem.nextSibling)
    {
      // scan for span or div tag
      if (!currentItem.tagName)
        continue;
      if (currentItem.className == 'cmNoClick')
      {
        item[0] = _cmNoClick;
        item[1] = getActionHTML (currentItem);
        hasAction = true;
        break;
      }
      if (currentItem.className == 'cmNoAction')
      {
        item[0] = _cmNoAction;
        item[1] = getActionHTML (currentItem);
        hasAction = true;
        break;
      }
      var tag = currentItem.tagName.toLowerCase ();
      if (tag != 'span')
        continue;
      if (!currentItem.firstChild)
        item[0] = null;
      else
        item[0] = currentItem.innerHTML;
      currentItem = currentItem.nextSibling;
      break;
    }
    if (hasAction)
    {
      items[items.length] = item;
      continue;
    }
    if (!currentItem)
      continue;
    for (; currentItem; currentItem = currentItem.nextSibling)
    {
      if (!currentItem.tagName)
        continue;
      var tag = currentItem.tagName.toLowerCase ();
      if (tag == 'a')
      {
        item[1] = currentItem.innerHTML;
        item[2] = currentItem.href;
        item[3] = currentItem.target;
        item[4] = currentItem.title;
        if (item[4] == '')
          item[4] = null;
      }
      else if (tag == 'span' || tag == 'div')
      {
        item[1] = currentItem.innerHTML;
        item[2] = null;
        item[3] = null;
        item[4] = null;
      }
      break;
    }

    for (; currentItem; currentItem = currentItem.nextSibling)
    {
      // scan for span tag
      if (!currentItem.tagName)
        continue;
      var tag = currentItem.tagName.toLowerCase ();
      if (tag != 'ul' && tag != 'ol')
        continue;
      var subMenuItems = cmDrawFromTextSubMenu (currentItem);
      for (i = 0; i < subMenuItems.length; ++i)
        item[i + 5] = subMenuItems[i];
      break;
    }
    items[items.length] = item;
  }
  return items;
}

//
// obtain the actual action item's action, which is inside a
// table.  The first row should be it
//
function getActionHTML (htmlNode)
{
  var returnVal = '<td></td><td></td><td></td>';
  var currentDomItem;
  // find the table first
  for (currentDomItem = htmlNode.firstChild; currentDomItem; currentDomItem = currentDomItem.nextSibling)
  {
    if (currentDomItem.tagName && currentDomItem.tagName.toLowerCase () == 'table')
      break;
  }
  if (!currentDomItem)
    return returnVal;
  // skip over tbody
  for (currentDomItem = currentDomItem.firstChild; currentDomItem; currentDomItem = currentDomItem.nextSibling)
  {
    if (currentDomItem.tagName && currentDomItem.tagName.toLowerCase () == 'tbody')
      break;
  }
  if (!currentDomItem)
    return returnVal;
  // get the first tr
  for (currentDomItem = currentDomItem.firstChild; currentDomItem; currentDomItem = currentDomItem.nextSibling)
  {
    if (currentDomItem.tagName && currentDomItem.tagName.toLowerCase () == 'tr')
      break;
  }
  if (!currentDomItem)
    return returnVal;
  return currentDomItem.innerHTML;
}

//
// get the DOM object associated with the item
//
function cmGetMenuItem (item)
{
  if (!item.subMenuID)
    return null;
  var subMenu = cmGetObject (item.subMenuID);
  // we are dealing with a main menu item
  if (item.menu)
  {
    var menu = item.menu;
    // skip over table, tbody, tr, reach td
    subMenu = subMenu.firstChild.firstChild.firstChild.firstChild;
    var i;
    for (i = 0; i < menu.length; ++i)
    {
      if (menu[i] == item)
        return subMenu;
      subMenu = subMenu.nextSibling;
    }
  }
  else if (item.parentItem) // sub menu item
  {
    var menu = item.parentItem;
    var table = cmGetObject (item.subMenuID + 'Table');
    if (!table)
      return null;
    // skip over table, tbody, reach tr
    subMenu = table.firstChild.firstChild;
    var i;
    for (i = 5; i < menu.length; ++i)
    {
      if (menu[i] == item)
        return subMenu;
      subMenu = subMenu.nextSibling;
    }
  }
  return null;
}

//
// disable a menu item
//
function cmDisableItem (item, prefix)
{
  if (!item)
    return;
  var menuItem = cmGetMenuItem (item);
  if (!menuItem)
    return;
  if (item.menu)
    menuItem.className = prefix + 'MainItemDisabled';
  else
    menuItem.className = prefix + 'MenuItemDisabled';
  item.isDisabled = true;
}

//
// enable a menu item
//
function cmEnableItem (item, prefix)
{
  if (!item)
    return;
  var menuItem = cmGetMenuItem (item);
  if (!menuItem)
    return;
  if (item.menu)
    menu.className = prefix + 'MainItem';
  else
    menu.className = prefix + 'MenuItem';
  item.isDisabled = false;
}

//////////////////////////////////////////////////////////////////////
//
// Mouse Event Handling Functions
//
//////////////////////////////////////////////////////////////////////

//
// action should be taken for mouse moving in to the menu item
//
// Here we just do things concerning this menu item, w/o opening sub menus.
//
function cmItemMouseOver (obj, isMain, idSub, menuID, index, calledByOpenSub)
{
  if (!calledByOpenSub && _cmClicked)
  {
    cmItemMouseOverOpenSub (obj, isMain, idSub, menuID, index);
    return;
  }

  clearTimeout (_cmTimeOut);

  if (_cmItemList[index].isDisabled)
    return;

  var prefix = _cmMenuList[menuID].prefix;

  if (!obj.cmMenuID)
  {
    obj.cmMenuID = menuID;
    obj.cmIsMain = isMain;
  }

  var thisMenu = cmGetThisMenu (obj, prefix);

  // insert obj into cmItems if cmItems doesn't have obj
  if (!thisMenu.cmItems)
    thisMenu.cmItems = new Array ();
  var i;
  for (i = 0; i < thisMenu.cmItems.length; ++i)
  {
    if (thisMenu.cmItems[i] == obj)
      break;
  }
  if (i == thisMenu.cmItems.length)
  {
    //thisMenu.cmItems.push (obj);
    thisMenu.cmItems[i] = obj;
  }

  // hide the previous submenu that is not this branch
  if (_cmCurrentItem)
  {
    // occationally, we get this case when user
    // move the mouse slowly to the border
    if (_cmCurrentItem == obj || _cmCurrentItem == thisMenu)
    {
      var item = _cmItemList[index];
      cmSetStatus (item);
      return;
    }

    var thatMenuInfo = _cmMenuList[_cmCurrentItem.cmMenuID];
    var thatPrefix = thatMenuInfo.prefix;
    var thatMenu = cmGetThisMenu (_cmCurrentItem, thatPrefix);

    if (thatMenu != thisMenu.cmParentMenu)
    {
      if (_cmCurrentItem.cmIsMain)
        _cmCurrentItem.className = thatPrefix + 'MainItem';
      else
        _cmCurrentItem.className = thatPrefix + 'MenuItem';
      if (thatMenu.id != idSub)
        cmHideMenu (thatMenu, thisMenu, thatMenuInfo);
    }
  }

  // okay, set the current menu to this obj
  _cmCurrentItem = obj;

  // just in case, reset all items in this menu to MenuItem
  cmResetMenu (thisMenu, prefix);

  var item = _cmItemList[index];
  var isDefaultItem = cmIsDefaultItem (item);

  if (isDefaultItem)
  {
    if (isMain)
      obj.className = prefix + 'MainItemHover';
    else
      obj.className = prefix + 'MenuItemHover';
  }

  cmSetStatus (item);
}

//
// action should be taken for mouse moving in to the menu item
//
// This function also opens sub menu
//
function cmItemMouseOverOpenSub (obj, isMain, idSub, menuID, index)
{
  clearTimeout (_cmTimeOut);

  if (_cmItemList[index].isDisabled)
    return;

  cmItemMouseOver (obj, isMain, idSub, menuID, index, true);

  if (idSub)
  {
    var subMenu = cmGetObject (idSub);
    var menuInfo = _cmMenuList[menuID];
    var orient = menuInfo.orient;
    var prefix = menuInfo.prefix;
    cmShowSubMenu (obj, isMain, subMenu, menuInfo);
  }
}

//
// action should be taken for mouse moving out of the menu item
//
function cmItemMouseOut (obj, isMain, idSub, menuID, index)
{
  var delayTime = _cmMenuList[menuID].nodeProperties.delay;
  _cmTimeOut = window.setTimeout ('cmHideMenuTime ()', delayTime);
  window.defaultStatus = '';
}

//
// action should be taken for mouse button down at a menu item
//
function cmItemMouseDown (obj, isMain, idSub, menuID, index)
{
  if (_cmItemList[index].isDisabled)
    return;

  if (cmIsDefaultItem (_cmItemList[index]))
  {
    var prefix = _cmMenuList[menuID].prefix;
    if (obj.cmIsMain)
      obj.className = prefix + 'MainItemActive';
    else
      obj.className = prefix + 'MenuItemActive';
  }
}

//
// action should be taken for mouse button down at a menu item
// this is one also opens submenu if needed
//
function cmItemMouseDownOpenSub (obj, isMain, idSub, menuID, index)
{
  if (_cmItemList[index].isDisabled)
    return;

  _cmClicked = true;
  cmItemMouseDown (obj, isMain, idSub, menuID, index);

  if (idSub)
  {
    var subMenu = cmGetObject (idSub);
    var menuInfo = _cmMenuList[menuID];
    cmShowSubMenu (obj, isMain, subMenu, menuInfo);
  }
}

//
// action should be taken for mouse button up at a menu item
//
function cmItemMouseUp (obj, isMain, idSub, menuID, index)
{
  if (_cmItemList[index].isDisabled)
    return;

  var item = _cmItemList[index];

  var link = null, target = '_self';

  if (item.length > 2)
    link = item[2];
  if (item.length > 3 && item[3])
    target = item[3];

  if (link != null)
  {
    _cmClicked = false;
    window.open (link, target);
  }

  var menuInfo = _cmMenuList[menuID];
  var prefix = menuInfo.prefix;
  var thisMenu = cmGetThisMenu (obj, prefix);

  var hasChild = (item.length > 5);
  if (!hasChild)
  {
    if (cmIsDefaultItem (item))
    {
      if (obj.cmIsMain)
        obj.className = prefix + 'MainItem';
      else
        obj.className = prefix + 'MenuItem';
    }
    cmHideMenu (thisMenu, null, menuInfo);
  }
  else
  {
    if (cmIsDefaultItem (item))
    {
      if (obj.cmIsMain)
        obj.className = prefix + 'MainItemHover';
      else
        obj.className = prefix + 'MenuItemHover';
    }
  }
}

//////////////////////////////////////////////////////////////////////
//
// Mouse Event Support Utility Functions
//
//////////////////////////////////////////////////////////////////////

//
// move submenu to the appropriate location
//
function cmMoveSubMenu (obj, isMain, subMenu, menuInfo)
{
  var orient = menuInfo.orient;

  var offsetAdjust;

  if (isMain)
  {
    if (orient.charAt (0) == 'h')
      offsetAdjust = menuInfo.nodeProperties.offsetHMainAdjust;
    else
      offsetAdjust = menuInfo.nodeProperties.offsetVMainAdjust;
  }
  else
    offsetAdjust = menuInfo.nodeProperties.offsetSubAdjust;

  if (!isMain && orient.charAt (0) == 'h')
    orient = 'v' + orient.charAt (1) + orient.charAt (2);

  var mode = String (orient);
  var p = subMenu.offsetParent;
  var subMenuWidth = cmGetWidth (subMenu);
  var horiz = cmGetHorizontalAlign (obj, mode, p, subMenuWidth);
  if (mode.charAt (0) == 'h')
  {
    if (mode.charAt (1) == 'b')
      subMenu.style.top = (cmGetYAt (obj, p) + cmGetHeight (obj) + offsetAdjust[1]) + 'px';
    else
      subMenu.style.top = (cmGetYAt (obj, p) - cmGetHeight (subMenu) - offsetAdjust[1]) + 'px';
    if (horiz == 'r')
      subMenu.style.left = (cmGetXAt (obj, p) + offsetAdjust[0]) + 'px';
    else
      subMenu.style.left = (cmGetXAt (obj, p) + cmGetWidth (obj) - subMenuWidth - offsetAdjust[0]) + 'px';
  }
  else
  {
    if (horiz == 'r')
      subMenu.style.left = (cmGetXAt (obj, p) + cmGetWidth (obj) + offsetAdjust[0]) + 'px';
    else
      subMenu.style.left = (cmGetXAt (obj, p) - subMenuWidth - offsetAdjust[0]) + 'px';
    if (mode.charAt (1) == 'b')
      subMenu.style.top = (cmGetYAt (obj, p) + offsetAdjust[1]) + 'px';
    else
      subMenu.style.top = (cmGetYAt (obj, p) + cmGetHeight (obj) - cmGetHeight (subMenu) + offsetAdjust[1]) + 'px';
  }

  // IE specific iframe masking method
  /*@cc_on
    @if (@_jscript_version >= 5.5)
      if (menuInfo.cmFrameMasking)
      {
        if (!subMenu.cmFrameObj)
        {
          var frameObj = cmAllocFrame ();
          subMenu.cmFrameObj = frameObj;
        }

        var frameObj = subMenu.cmFrameObj;
        frameObj.style.zIndex = subMenu.style.zIndex - 1;
        frameObj.style.left = (cmGetX (subMenu) - cmGetX (frameObj.offsetParent)) + 'px';
        frameObj.style.top = (cmGetY (subMenu)  - cmGetY (frameObj.offsetParent)) + 'px';
        frameObj.style.width = cmGetWidth (subMenu) + 'px';
        frameObj.style.height = cmGetHeight (subMenu) + 'px';
        frameObj.style.display = 'block';
      }
    @end
  @*/
  if (horiz != orient.charAt (2))
    orient = orient.charAt (0) + orient.charAt (1) + horiz;
  return orient;
}

//
// automatically re-adjust the menu position based on available screen size.
//
function cmGetHorizontalAlign (obj, mode, p, subMenuWidth)
{
  var horiz = mode.charAt (2);
  if (!(document.body))
    return horiz;
  var body = document.body;
  var browserLeft;
  var browserRight;
  if (window.innerWidth)
  {
    // DOM window attributes
    browserLeft = window.pageXOffset;
    browserRight = window.innerWidth + browserLeft;
  }
  else if (body.clientWidth)
  {
    // IE attributes
    browserLeft = body.clientLeft;
    browserRight = body.clientWidth + browserLeft;
  }
  else
    return horiz;
  if (mode.charAt (0) == 'h')
  {
    if (horiz == 'r' && (cmGetXAt (obj) + subMenuWidth) > browserRight)
      horiz = 'l';
    if (horiz == 'l' && (cmGetXAt (obj) + cmGetWidth (obj) - subMenuWidth) < browserLeft)
      horiz = 'r';
    return horiz;
  }
  else
  {
    if (horiz == 'r' && (cmGetXAt (obj, p) + cmGetWidth (obj) + subMenuWidth) > browserRight)
      horiz = 'l';
    if (horiz == 'l' && (cmGetXAt (obj, p) - subMenuWidth) < browserLeft)
      horiz = 'r';
    return horiz;
  }
}

//
// show the subMenu w/ specified orientation
// also move it to the correct coordinates
//
function cmShowSubMenu (obj, isMain, subMenu, menuInfo)
{
  var prefix = menuInfo.prefix;

  if (!subMenu.cmParentMenu)
  {
    // establish the tree w/ back edge
    var thisMenu = cmGetThisMenu (obj, prefix);
    subMenu.cmParentMenu = thisMenu;
    if (!thisMenu.cmSubMenu)
      thisMenu.cmSubMenu = new Array ();
    thisMenu.cmSubMenu[thisMenu.cmSubMenu.length] = subMenu;
  }

  var effectInstance = subMenu.cmEffect;
  if (effectInstance)
    effectInstance.showEffect (true);
  else
  {
    // position the sub menu only if we are not already showing the submenu
    var orient = cmMoveSubMenu (obj, isMain, subMenu, menuInfo);
    subMenu.cmOrient = orient;

    var forceShow = false;
    if (subMenu.style.visibility != 'visible' && menuInfo.nodeProperties.effect)
    {
      try
      {
        effectInstance = menuInfo.nodeProperties.effect.getInstance (subMenu, orient);
        effectInstance.showEffect (false);
      }
      catch (e)
      {
        forceShow = true;
        subMenu.cmEffect = null;
      }
    }
    else
      forceShow = true;

    if (forceShow)
    {
      subMenu.style.visibility = 'visible';
      /*@cc_on
        @if (@_jscript_version >= 5.5)
          if (subMenu.cmFrameObj)
            subMenu.cmFrameObj.style.display = 'block';
        @end
      @*/
    }
  }

  if (!_cmHideObjects)
  {
    _cmHideObjects = 2; // default = not hide, may change behavior later
    try
    {
      if (window.opera)
      {
        if (parseInt (navigator.appVersion) < 9)
          _cmHideObjects = 1;
      }
    }
    catch (e)
    {
    }
  }

  if (_cmHideObjects == 1)
  {
    if (!subMenu.cmOverlap)
      subMenu.cmOverlap = new Array ();
    cmHideControl ("IFRAME", subMenu);
    cmHideControl ("OBJECT", subMenu);
  }
}

//
// reset all the menu items to class MenuItem in thisMenu
//
function cmResetMenu (thisMenu, prefix)
{
  if (thisMenu.cmItems)
  {
    var i;
    var str;
    var items = thisMenu.cmItems;
    for (i = 0; i < items.length; ++i)
    {
      if (items[i].cmIsMain)
      {
        if (items[i].className == (prefix + 'MainItemDisabled'))
          continue;
      }
      else
      {
        if (items[i].className == (prefix + 'MenuItemDisabled'))
          continue;
      }
      if (items[i].cmIsMain)
        str = prefix + 'MainItem';
      else
        str = prefix + 'MenuItem';
      if (items[i].className != str)
        items[i].className = str;
    }
  }
}

//
// called by the timer to hide the menu
//
function cmHideMenuTime ()
{
  _cmClicked = false;
  if (_cmCurrentItem)
  {
    var menuInfo = _cmMenuList[_cmCurrentItem.cmMenuID];
    var prefix = menuInfo.prefix;
    cmHideMenu (cmGetThisMenu (_cmCurrentItem, prefix), null, menuInfo);
    _cmCurrentItem = null;
  }
}

//
// Only hides this menu
//
function cmHideThisMenu (thisMenu, menuInfo)
{
  var effectInstance = thisMenu.cmEffect;
  if (effectInstance)
    effectInstance.hideEffect (true);
  else
  {
    thisMenu.style.visibility = 'hidden';
    thisMenu.style.top = '0px';
    thisMenu.style.left = '0px';
    thisMenu.cmOrient = null;
    /*@cc_on
      @if (@_jscript_version >= 5.5)
        if (thisMenu.cmFrameObj)
        {
          var frameObj = thisMenu.cmFrameObj;
          frameObj.style.display = 'none';
          frameObj.style.width = '1px';
          frameObj.style.height = '1px';
          thisMenu.cmFrameObj = null;
          cmFreeFrame (frameObj);
        }
      @end
    @*/
  }

  cmShowControl (thisMenu);
  thisMenu.cmItems = null;
}

//
// hide thisMenu, children of thisMenu, as well as the ancestor
// of thisMenu until currentMenu is encountered.  currentMenu
// will not be hidden
//
function cmHideMenu (thisMenu, currentMenu, menuInfo)
{
  var prefix = menuInfo.prefix;
  var str = prefix + 'SubMenu';

  // hide the down stream menus
  if (thisMenu.cmSubMenu)
  {
    var i;
    for (i = 0; i < thisMenu.cmSubMenu.length; ++i)
    {
      cmHideSubMenu (thisMenu.cmSubMenu[i], menuInfo);
    }
  }

  // hide the upstream menus
  while (thisMenu && thisMenu != currentMenu)
  {
    cmResetMenu (thisMenu, prefix);
    if (thisMenu.className == str)
    {
      cmHideThisMenu (thisMenu, menuInfo);
    }
    else
      break;
    thisMenu = cmGetThisMenu (thisMenu.cmParentMenu, prefix);
  }
}

//
// hide thisMenu as well as its sub menus if thisMenu is not
// already hidden
//
function cmHideSubMenu (thisMenu, menuInfo)
{
  if (thisMenu.style.visibility == 'hidden')
    return;
  if (thisMenu.cmSubMenu)
  {
    var i;
    for (i = 0; i < thisMenu.cmSubMenu.length; ++i)
    {
      cmHideSubMenu (thisMenu.cmSubMenu[i], menuInfo);
    }
  }
  var prefix = menuInfo.prefix;
  cmResetMenu (thisMenu, prefix);
  cmHideThisMenu (thisMenu, menuInfo);
}

//
// hide a control such as IFRAME
//
function cmHideControl (tagName, subMenu)
{
  var x = cmGetX (subMenu);
  var y = cmGetY (subMenu);
  var w = subMenu.offsetWidth;
  var h = subMenu.offsetHeight;

  var i;
  for (i = 0; i < document.all.tags(tagName).length; ++i)
  {
    var obj = document.all.tags(tagName)[i];
    if (!obj || !obj.offsetParent)
      continue;

    // check if the object and the subMenu overlap

    var ox = cmGetX (obj);
    var oy = cmGetY (obj);
    var ow = obj.offsetWidth;
    var oh = obj.offsetHeight;

    if (ox > (x + w) || (ox + ow) < x)
      continue;
    if (oy > (y + h) || (oy + oh) < y)
      continue;

    // if object is already made hidden by a different
    // submenu then we dont want to put it on overlap list of
    // of a submenu a second time.
    // - bug fixed by Felix Zaslavskiy
    if(obj.style.visibility == 'hidden')
      continue;

    //subMenu.cmOverlap.push (obj);
    subMenu.cmOverlap[subMenu.cmOverlap.length] = obj;
    obj.style.visibility = 'hidden';
  }
}

//
// show the control hidden by the subMenu
//
function cmShowControl (subMenu)
{
  if (subMenu.cmOverlap)
  {
    var i;
    for (i = 0; i < subMenu.cmOverlap.length; ++i)
      subMenu.cmOverlap[i].style.visibility = "";
  }
  subMenu.cmOverlap = null;
}

//
// returns the main menu or the submenu table where this obj (menu item)
// is in
//
function cmGetThisMenu (obj, prefix)
{
  var str1 = prefix + 'SubMenu';
  var str2 = prefix + 'Menu';
  while (obj)
  {
    if (obj.className == str1 || obj.className == str2)
      return obj;
    obj = obj.parentNode;
  }
  return null;
}

//
// A special effect function to hook the menu which contains
// special effect object to the timer.
//
function cmTimeEffect (menuID, show, delayTime)
{
  window.setTimeout ('cmCallEffect("' + menuID + '",' + show + ')', delayTime);
}

//
// A special effect function.  Called by timer.
//
function cmCallEffect (menuID, show)
{
  var menu = cmGetObject (menuID);
  if (!menu || !menu.cmEffect)
    return;
  try
  {
    if (show)
      menu.cmEffect.showEffect (false);
    else
      menu.cmEffect.hideEffect (false);
  }
  catch (e)
  {
  }
}

//
// return true if this item is handled using default handlers
//
function cmIsDefaultItem (item)
{
  if (item == _cmSplit || item[0] == _cmNoAction || item[0] == _cmNoClick)
    return false;
  return true;
}

//
// returns the object baring the id
//
function cmGetObject (id)
{
  if (document.all)
    return document.all[id];
  return document.getElementById (id);
}

//
// functions that obtain the width of an HTML element.
//
function cmGetWidth (obj)
{
  var width = obj.offsetWidth;
  if (width > 0 || !cmIsTRNode (obj))
    return width;
  if (!obj.firstChild)
    return 0;
  // use TABLE's length can cause an extra pixel gap
  //return obj.parentNode.parentNode.offsetWidth;

  // use the left and right child instead
  return obj.lastChild.offsetLeft - obj.firstChild.offsetLeft + cmGetWidth (obj.lastChild);
}

//
// functions that obtain the height of an HTML element.
//
function cmGetHeight (obj)
{
  var height = obj.offsetHeight;
  if (height > 0 || !cmIsTRNode (obj))
    return height;
  if (!obj.firstChild)
    return 0;
  // use the first child's height
  return obj.firstChild.offsetHeight;
}

//
// functions that obtain the coordinates of an HTML element
//
function cmGetX (obj)
{
  if (!obj)
    return 0;
  var x = 0;

  do
  {
    x += obj.offsetLeft;
    obj = obj.offsetParent;
  }
  while (obj);
  return x;
}

function cmGetXAt (obj, elm)
{
  var x = 0;

  while (obj && obj != elm)
  {
    x += obj.offsetLeft;
    obj = obj.offsetParent;
  }
  if (obj == elm)
    return x;
  return x - cmGetX (elm);
}

function cmGetY (obj)
{
  if (!obj)
    return 0;
  var y = 0;
  do
  {
    y += obj.offsetTop;
    obj = obj.offsetParent;
  }
  while (obj);
  return y;
}

function cmIsTRNode (obj)
{
  var tagName = obj.tagName;
  return tagName == "TR" || tagName == "tr" || tagName == "Tr" || tagName == "tR";
}

//
// get the Y position of the object.  In case of TR element though,
// we attempt to adjust the value.
//
function cmGetYAt (obj, elm)
{
  var y = 0;

  if (!obj.offsetHeight && cmIsTRNode (obj))
  {
    var firstTR = obj.parentNode.firstChild;
    obj = obj.firstChild;
    y -= firstTR.firstChild.offsetTop;
  }

  while (obj && obj != elm)
  {
    y += obj.offsetTop;
    obj = obj.offsetParent;
  }

  if (obj == elm)
    return y;
  return y - cmGetY (elm);
}

//
// extract description from the menu item and set the status text
//
function cmSetStatus (item)
{
  var descript = '';
  if (item.length > 4)
    descript = (item[4] != null) ? item[4] : (item[2] ? item[2] : descript);
  else if (item.length > 2)
    descript = (item[2] ? item[2] : descript);

  window.defaultStatus = descript;
}

//
// debug function, ignore :)
//
function cmGetProperties (obj)
{
  if (obj == undefined)
    return 'undefined';
  if (obj == null)
    return 'null';

  var msg = obj + ':\n';
  var i;
  for (i in obj)
    msg += i + ' = ' + obj[i] + '; ';
  return msg;
}


