/* =========================================================================  *
* | iMenu v 2.0 - JavaScript Function/Variable Library                      | *
* | Developed by Jacob Kronika <jkronika@imagescape.com>                    | *
* | Copyright (c) 2005 Imaginary Landscape, LLC <www.imagescape.com>        | *
* | Reuse or modification without permission is prohibited                  | *
* | Revised 12 July 2005                                                    | *
*  ========================================================================= */

var iMenuOpen = []; // array of open menus
var iMenuWasOpen = {}; // associative array of menu_id:open_flag
var iMenuHShiftX = [], iMenuHShiftY = [], iMenuVShiftX = [], iMenuVShiftY = [],
    iMenuOpShiftY = [];
var iMenuAutoClose = false; // will menus close automatically or on user click
var iMenuHidePause = 300;
var iMenuTimer; // storage for setTimeout calls

/* find and prepare iMenus */
function iMenuInit() {
  var iMenus = docGetClass('ul','iMenu'); // top menu ULs

  if (typeof(iMenus) == 'undefined' || !iMenus || iMenus.length === 0) {
    return;
  }
  for (var i = 0; i < iMenus.length; i++) {
    iMenuHShiftX[i] = parseInt(iMenus[i].getAttribute('hShiftX')) || 0;
    iMenuHShiftY[i] = parseInt(iMenus[i].getAttribute('hShiftY')) || 0;
    iMenuVShiftX[i] = parseInt(iMenus[i].getAttribute('vShiftX')) || 0;
    iMenuVShiftY[i] = parseInt(iMenus[i].getAttribute('vShiftY')) || 0;
    iMenuOpShiftY[i] = parseInt(iMenus[i].getAttribute('operaShiftY')) || 0;
    iMenuAutoClose = (iMenus[i].getAttribute('autoclose') == 'true' ? true : false);
    iMenuHidePause = parseInt(iMenus[i].getAttribute('hidePause')) || 300;

    adjust_offset(i);

    iMenuAddProperties(iMenus[i], i, '');
    iMenuInitChildren(iMenus[i], i, '');
  }
}

function iMenuInitChildren(iMenuElem, index, path) {
  var iMenuChildren = [];
  var tmpChildren = iMenuElem.childNodes;

  for (var i = 0; i < tmpChildren.length; i++) {
    if (typeof(tmpChildren[i].tagName) != 'undefined') {
      if (iMenuElem.tagName.toLowerCase() == 'ul') {
	      iMenuAddProperties(tmpChildren[i], index, path+'-'+i);
      } else {
	      iMenuAddProperties(tmpChildren[i], index, path);
      }
    }
  }
}

/* add mouseovers, IDs, class names to the iMenu provided */
function iMenuAddProperties(iMenuElem, index, path) {
  if (typeof(iMenuElem.tagName) == 'undefined') {
    return;
  }
  switch(iMenuElem.tagName.toLowerCase()) {
  case 'ul':
    iMenuULAddProperties(iMenuElem, index, path);
    break;
  case 'li':
    iMenuLIAddProperties(iMenuElem, index, path);
    break;
  case 'a':
    iMenuAAddProperties(iMenuElem, index, path);
    break;
  default:
    return;
  }
}

/* add properties to this UL as follows:
* -UL top menu:
*     ID=iMenuX (where X is an index of iMenus on the page)
*     Class=PREDEFINED ('iMenu vertical' or 'iMenu horizontal')
* -UL submenu: ID=iMenuXSub-i-j-...-N, Class='iMenuSub vertical' */
function iMenuULAddProperties(iMenuUL, index, path) {
  if (iMenuUL.className.match(/\biMenu\b/)) { // top menu UL
    iMenuUL.id = 'iMenu'+index;
    if (is_mac && is_ie) { iMenuUL.style.visibility = 'visible'; }
  } else {
    iMenuUL.id = 'iMenu'+index+'Sub'+path;
    iMenuUL.className += ' iMenuSub vertical';
    iMenuInitChildren(iMenuUL, index, path);
  }
  iMenuWasOpen[iMenuUL.id] = false;
}

/* add properties to this LI as follows:
* -LI: ID=iMenuXNode-i-j-...-N, Class='iMenuNode' */
function iMenuLIAddProperties(iMenuLI, index, path) {
  iMenuLI.id = 'iMenu'+index+'Node'+path;
  iMenuLI.className += ' iMenuNode';
  iMenuInitChildren(iMenuLI, index, path);
}

/* add properties to this A as follows:
* -A: ID=iMenuXLink, Class='iMenuLink'
*     mouseover = iMenuShow('iMenuXSub-i-j-...-N') */
function iMenuAAddProperties(iMenuA, index, path) {
  iMenuA.id = 'iMenu'+index+'Link'+path;
  iMenuA.className += ' iMenuLink';

  var iMenuLI = get_parent(iMenuA, 'li');
  if (iMenuLI.getElementsByTagName('ul').length > 0) {
    iMenuA.className += ' has-sub';
    if (is_op || (is_ns && !is_ns8) || ((is_mac && is_ff) || is_saf)) {
      iMenuA.innerHTML += '<nobr> &nbsp; &raquo;</nobr>';
    }
  }

  if (Boolean(docGetID('iMenu'+index).getAttribute('requireclick'))) {
    iMenuA.onclick = function() {
      iMenuShow('iMenu'+index+'Sub'+path);
      return false;
    };
    iMenuA.onmouseover = function() {
      if (is_ie) {
	      this.className += ' iMenuHover';
      }
      if (iMenuOpen.length > 0) {
	      return iMenuShow('iMenu'+index+'Sub'+path);
      } else {
	      return false;
      }
    };
  } else {
    iMenuA.onmouseover = function() {
      if (is_ie) {
	      get_parent(this, 'li').className += ' iMenuHover';
      }
      return iMenuShow('iMenu'+index+'Sub'+path);
    };
  }


  if (is_ie) {
    iMenuA.onmouseout = function() {
      get_parent(this, 'li').className =
      get_parent(this, 'li').className.replace(/\biMenuHover\b/, '');
      if(iMenuAutoClose) {
        iMenuTimer = setTimeout('iMenuHideAll()', 300);
      }
    };
  } else {
    iMenuA.onmouseout = function() {
      if(iMenuAutoClose) {
        iMenuTimer = setTimeout('iMenuHideAll()', 300);
      }
    };
  }
}

// position the menu with the ID provided according to its parent menu
function iMenuPosition(iMenuID) {
  if (iMenuID.search(/^iMenu[0-9]+$/) > -1) {
    // top menu
    return;
  }
  var index = parseInt(iMenuID.substring(5, iMenuID.indexOf('Sub')));

  var iMenu = docGetID(iMenuID);
  if (!iMenu) {
    // no such menu
    return;
  }

  iMenu.style.left = get_offset_left(iMenu, index) + 'px';
  iMenu.style.top = get_offset_top(iMenu, index) + 'px';
}

function iMenuRePosition() {
  iMenuHideAll();
  for (iMenuUL in iMenuWasOpen) {
    if (iMenuWasOpen[iMenuUL]) {
      iMenuWasOpen[iMenuUL] = false;
      docGetID(iMenuUL).style.left = null;
      docGetID(iMenuUL).style.top = null;
    }
  }
}

/* if already shown, do nothing
* if top/left are empty, position the menu with the ID provided
* show the menu with the ID provided
* add the ID provided to the iMenuOpen array */
function iMenuShow(iMenuID) {
  clearTimeout(iMenuTimer);

  if (iMenuOpen.length < 1) {
    toggle_select_boxes(false);
  }

  for (var i = iMenuOpen.length-1; i >= 0; i--) {
    if (iMenuID == iMenuOpen[i]) {
      return true;
    } else if (iMenuOpen[i].substring(0,iMenuOpen[i].indexOf('-')) !=
	       iMenuID.substring(0,iMenuID.indexOf('-'))) {
      iMenuHide(iMenuOpen[i]);
    } else if (iMenuOpen[i].indexOf(iMenuID) > -1) {
      iMenuHide(iMenuOpen[i]);
    } else if (iMenuOpen[i].length > iMenuID.length ||
	       (iMenuOpen[i].length < iMenuID.length &&
		iMenuOpen[i].substring(0,iMenuOpen[i].lastIndexOf('-')) ==
		iMenuID.substring(0,iMenuID.lastIndexOf('-')))) {
      iMenuHide(iMenuOpen[i]);
    } else if (iMenuOpen[i].length == iMenuID.length &&
	       iMenuOpen[i].substring(0, iMenuOpen[i].lastIndexOf('-')) ==
	       iMenuID.substring(0, iMenuID.lastIndexOf('-'))) {
      iMenuHide(iMenuOpen[i]);
    }
  }
  var iMenu = docGetID(iMenuID);
  if (!iMenu) {
    // no such menu
    return null;
  }
  if (!iMenuWasOpen[iMenuID]) {
    iMenuPosition(iMenuID);
  }

  docGetID(iMenuID).style.visibility = 'visible';
  iMenuOpen[iMenuOpen.length] = iMenuID; // add to end of array of open menus
  iMenuWasOpen[iMenuID] = true; // change flag to reflect this menu was opened
  return null;
}

/* hide the menu with the ID provided, and all of its submenus
 * remove the IDs of the hidden menus from the iMenuOpen array */
function iMenuHide(iMenuID) {
  if (iMenuID.search(/^iMenu[0-9]+$/) > -1) {
    // top level menu
    return;
  }

  docGetID(iMenuID).style.visibility = 'hidden';
  for (var i = iMenuOpen.length-1; i >= 0; i--) {
    if (iMenuOpen[i] == iMenuID) {
      iMenuOpen.length--;
    } else if (iMenuOpen[i].indexOf(iMenuID) > -1) {
      iMenuHide(iMenuOpen[i]);
    }
  }

  if (iMenuOpen.length < 1) {
    toggle_select_boxes(true);
  }
}

function iMenuHideAll() {
  for (var i = 0; i < iMenuOpen.length; i++) {
    docGetID(iMenuOpen[i]).style.visibility = 'hidden';
  }

  toggle_select_boxes(true);

  iMenuOpen.length = 0;
}

function iMenuPageClick(event) {
  var el;
  if (! iMenuOpen.length) {
    return;
  }

  // Find the element that was clicked on.
  if (window.event) {
    el = window.event.srcElement;
  } else {
    el = (event.target.tagName ? event.target : event.target.parentNode);
  }

  // if an open menu was clicked on, exit
  for (var i = 0; i < iMenuOpen.length; i++) {
    if (typeof(el.id) != 'undefined' && el.id == iMenuOpen[i]) {
      return;
    }
  }

  // if the element is not part of a menu, reset and clear the active button
  var node = el;
  while (node) {
    if (node.tagName !== null && node.tagName == 'A' &&
	node.className.match(/\biMenuLink\b/)) { // The click was part of a menu
      return;
    }
    node = node.parentNode;
  }

  // The click was not on a menu
  iMenuHideAll();
}

/* ********************************
* UTILITY VARIABLES AND FUNCTIONS *
******************************** */
/* browser detection variables */
var agent    = navigator.userAgent.toLowerCase(), // browser data
    is_mac   = agent.indexOf('mac') > -1,         // Macintosh operating system
    is_msie  = agent.indexOf('msie') > -1,        // MSIE rendering engine
    is_op    = agent.indexOf('opera') > -1,       // Opera browser
    is_ie    = is_msie && !is_op,                 // IE browser
    is_gecko = agent.indexOf('gecko') > -1,       // Gecko rendering engine
    is_ns    = agent.indexOf('netscape') > -1,    // Netscape browser
    is_ns8   = agent.indexOf('netscape/8') > -1,  // Netscape v8 browser
    is_ff    = agent.indexOf('firefox') > -1,     // Firefox browser
    is_moz   = is_gecko && !is_ns && !is_ff,      // Mozilla browser
    is_saf   = agent.indexOf('safari') > -1;      // Safari browser

function get_parent(elem, tag) {
  if (typeof(tag) == 'undefined') {
    return elem.parentNode;
  } else {
    var parent = elem.parentNode;
    while (parent.tagName.toLowerCase() != tag) {
      parent = parent.parentNode;
      if (parent.tagName.toLowerCase == 'body') {
	return null;
      }
    }
    return parent;
  }
}

function get_offset_top(el, index) {
  var parentUL = get_parent(el, 'ul'), parentLI = get_parent(el, 'li'),
      parentA = parentLI.childNodes[0], y = 0, i = 0;
  while (typeof(parentA.tagName) == 'undefined' &&
	++i < parentLI.childNodes.length) {
    parentA = parentLI.childNodes[i];
  }

  y = el.offsetTop +
    (typeof(parentUL.className) != 'undefined' &&
     parentUL.className.search(/\bhorizontal\b/) > -1 ? // horizontal menu
     (is_op ?
      parentLI.offsetHeight + (2*parentA.offsetHeight) + iMenuHShiftY[index] :
      iMenuHShiftY[index]) :
     iMenuVShiftY[index] - parentLI.offsetHeight);
  return y;
}

function get_offset_left(el, index) {
  var parentUL = get_parent(el, 'ul'), parentLI = get_parent(el, 'li'), x;

  x = el.offsetLeft +
    (typeof(parentUL.className) != 'undefined' &&
     parentUL.className.search(/\bhorizontal\b/) > -1 ? // horizontal menu
     iMenuHShiftX[index] : iMenuVShiftX[index] +
     (is_ie ? 0 : parentLI.offsetWidth));
  if(is_ie) x += parentLI.offsetWidth;
  if(is_ie && parentUL.className.match(/\biMenu\b/)) x += 9;
  return x;
}
/*
function verify_offset(index) {
  if (!isFinite(iMenuHShiftX[index])) {
    iMenuHShiftX[index] = 0;
  }
  if (!isFinite(iMenuHShiftY[index])) {
    iMenuHShiftY[index] = 0;
  }
  if (!isFinite(iMenuVShiftX[index])) {
    iMenuVShiftX[index] = 0;
  }
  if (!isFinite(iMenuVShiftY[index])) {
    iMenuVShiftY[index] = 0;
  }
  if (!isFinite(iMenuOpShiftY[index])) {
    iMenuOpShiftY[index] = 0;
  }
} */

function adjust_offset(index) {
  // verify_offset(index);
  // ensure that all offsets are finite numbers (else use 0)
  iMenuHShiftX[index] -= 7;
  if (is_op) {
    iMenuHShiftY[index] += iMenuOpShiftY[index];
  } else {
    iMenuHShiftY[index] += 4;
  }
}

function toggle_select_boxes(vis) {
  if (!is_ie) {
    return;
  }
  var sel = docGetTags('select');
  for (var i = 0; i < sel.length; i++) {
    sel[i].style.visibility = (vis ? 'visible' : 'hidden');
  }
}

/*******************************************************************************
 * docGetID()
 * Retrieve document elements by ID attribute
 *
 * Developed by Jacob Kronika <jkronika@imagescape.com>
 * Copyright 2005 Imaginary Landscape, LLC <www.imagescape.com>
 * Reuse or modification without permission is prohibited
 * Revised: 2005 May 26
 *
 * shortcut function to document.getElementById(id)
 * provides additional functionality in that a list of different
 * IDs can be included as arguments to the function, and the result is
 * then returned as an array of corresponding objects
 ******************************************************************************/
function docGetID() {
  if (typeof(document.getElementById) == 'undefined') {
    document.getElementById = function() {
      return null;
    };
  }

  if (arguments.length < 1) {
    /* if there are zero or undefined arguments, no object can be retrieved */
    return false;
  } else if (arguments.length == 1) {
    /* if there is one argument, return the object with that ID */
    return document.getElementById(arguments[0]);
  } else {
    /* if there are multiple arguments, fill an array with objects returned
     * by recursive calls to docGetId
     * NOTE: using this implementation, infinitely nested arrays of IDs can be
     * used to retrieve a corresponding hierarchy of objects */
    var tmpArray = new Array();               // create a temporary array

    for (var i = 0; i < arguments.length; i++) { // traverse the arguments
      /* add the result of a docGetID call using only the current argument to the
       * array at the position beyond the current last element */
      tmpArray[tmpArray.length] = docGetID(arguments[i]);
    }

    return tmpArray;                          // return the results
  }
}

/*******************************************************************************
 * docGetClass()
 * retrieve document elements by CSS class name
 *
 * Developed by Jacob Kronika <jkronika@imagescape.com>
 * Copyright 2005 Imaginary Landscape, LLC <www.imagescape.com>
 * Reuse or modification without permission is prohibited
 * Revised: 2005 May 26
 *
 * combines a call to docGetTags with a simple equality comparison of
 * strings to return an array of elements (of a given tag) that have a
 * given class name
 * provides additional functionality in that either a single string or an array
 * of different strings of tag names can be included as the first argument, and
 * a single string or an array of different strings of class names can be
 * included as the second argument. The result is then returned as a
 * hierarchical array of arrays of corresponding objects by class names within
 * arrays by tag name
 *
 * NOTE: REQUIRES docGetTags() [docGetTags.js]
 * NOT COMPATIBLE WITH WINDOWS OPERA 7.54
 ******************************************************************************/
function docGetClass() {
  var tags;                   // create a variable for tag name(s)
  var classes;                // create a variable for class name(s)

  if (arguments.length == 2) {
    /* if there are two arguments, assume arguments = [TAG_NAMES, CLASS_NAMES] */
    tags = docGetTags(arguments[0]);
    /* retrieve elements by tag name argument */
    classes = arguments[1];    // retrieve the class names argument
    if (tags.length < 1) {
      return false;
    }
  } else if (arguments.length == 1) {
    /* if there is one argument, assume arguments = [CLASS_NAMES] and tags should
     * include all elements by tag name in the document */
    tags = docGetTags();       // retrieve elements with any tag name
    classes = arguments[0];    // retrieve the class names argument
    if (tags.length < 1) {
      return false;
    }
  } else {
    /* if there are zero, greater than 2, or undefined arguments, no elements
     * can be returned */
    return false;
  }

  if (typeof(tags) == 'undefined' || tags.length < 1) {
    return false;
  } else if (typeof(classes) == 'string') {
    classes = [classes];
  } else {
    /* make sure that the tags and classes variables are set and are Arrays and not
     * strings */
    return false;
  }

  var tmpArray = []; // create a temporary array

  for (var i = 0; i < tags.length; i++) {
    // traverse the elements returned by docGetTag
    for (var j = 0; j < classes.length; j++) {
      // traverse the user-supplied class names
      if (typeof(tags[i].className) != 'undefined' &&
	  tags[i].className.search(new RegExp("\\b"+classes[j]+"\\b")) > -1) {
	// if the current element has the current class name
	tmpArray[tmpArray.length] = tags[i];
	/* add the current element to the temporary array at the position beyond the
	 * current last element */
      }
    }
  }
  return tmpArray;                         // return the results
}

/*******************************************************************************
 * docGetTags()
 * retrieve document elements by HTML tag name
 *
 * Developed by Jacob Kronika <jkronika@imagescape.com>
 * Copyright 2005 Imaginary Landscape, LLC <www.imagescape.com>
 * Reuse or modification without permission is prohibited
 * Revised: 2005 May 26
 *
 * shortcut function to document.getElementsByTagName(tag)
 * provides additional functionality in that a list of different tag names
 * can be included as arguments to the function, and the result is then
 * returned as an array of arrays of corresponding objects
 ******************************************************************************/
function docGetTags() {
  if (arguments.length < 1) {
    /* if there are zero or undefined arguments, return elements with any tag
     * name */
    return document.getElementsByTagName('*');
  } else if (arguments.length == 1) {
    /* if there is one argument, return the object with that HTML tag name */
    return document.getElementsByTagName(arguments[0]);
  } else {
    /* if there are multiple arguments, fill an array with objects returned
     * by recursive calls to docGetTags
     * NOTE: using this implementation, infinitely nested arrays of IDs can be
     * used to retrieve a corresponding hierarchy of objects */
    var tmpArray = new Array();               // create a temporary array

    for (var i = 0; i < arguments.length; i++) {
      // traverse the arguments
      tmpArray[tmpArray.length] = docGetTags(arguments[i]);
      /* add the result of a docGetTags call using only the current argument to
       * the array at the position beyond the current last element */
    }

    return tmpArray;                          // return the results
  }
}

// Capture mouse clicks on the page so any active button can be deactivated.
if (document.addEventListener) {
  document.addEventListener("mousedown", iMenuPageClick, true);
} else {
  document.onmousedown = iMenuPageClick;
}

// Load all the menus
if (window.attachEvent) {
  window.attachEvent("onload", iMenuInit);
} else {
  var preMenuOnload = window.onload;
  window.onload = function () {
    if (preMenuOnload) {
      preMenuOnload();
    }
    iMenuInit();
  };
}

if (window.attachEvent) {
  window.attachEvent("onresize", iMenuRePosition);
} else {
  var preSizeOnResize = window.onresize;
  window.onresize = function() {
    if (preSizeOnResize) {
      preSizeOnResize();
    }
    iMenuRePosition();
  };
}

