/** public static class Navigation : Encapsulates actions necessary for
  * using all consumer-facing navigation.
  */
Navigation = {
	/** public static final int FLOATING_SUBNAV_ZINDEX : z-index of floating subnavs. */
	FLOATING_SUBNAV_ZINDEX : 1000,
	/** public static final String GIF_SUFFIX : gif extension. */
	GIF_SUFFIX : ".gif",
	/** public static final String HIDE_CLASS : Class applied to subnav menus to hide them. */
	HIDE_CLASS : "navHidden",
	/** public static final String IMAGE_PREFIX : Prefix of nav item image names. */
	IMAGE_PREFIX : "image_",
	/** public static final String LIVE_SUFFIX : "live" gif image state extension. */
	LIVE_SUFFIX : ".live",
	/** public static final String MAINNAV_ITEM : Root of standard main item class names. */
	MAINNAV_ITEM : "mainnavItem",
	/** public static final RegExp MO_IMAGE_RE : Matches standard "over" gifs. */
	MO_IMAGE_RE : /\.mo\.gif/,
	/** public static final String MO_SUFFIX : "mouseover" gif image state extension. */
	MO_SUFFIX : ".mo",
	/** public static final String ON : Part of standard "live" class name. */
	ON : "On",
	/** public static final RegExp OUT_IMAGE_RE : Matches standard "out" gifs. */
	OUT_IMAGE_RE : /\.gif/,
	/** public static final String OUT_SUFFIX : "out" image state and class name part. */
	OUT_SUFFIX : "",
	/** public static final String OVER : Part of standard "over" class name. */
	OVER : "Over",
	/** public static final String SCREEN_SUFFIX : Suffix of iframe screen element ids. */
	SCREEN_SUFFIX : "_screen",
	/** public static final String SHOW_CLASS : Class applied to subnav menus to show them. */
	SHOW_CLASS : "navVisible",
	/** public static final String SUBNAV_ITEM : Root of standard sub item class names. */
	SUBNAV_ITEM : "subnavItem",
	/** public static final String SUBNAV_PREFIX : Prefix of subnav and screen element ids. */
	SUBNAV_PREFIX : "subnav_",
	
	/** private String displayedSectionId : id of currently displayed subnav menu. */
	displayedSectionId : null,
	/** private Map initializedItems : Map of initialized NavigationItemVOs, keyed by id. */
	initializedItems : {},
	/** private Map menuOffset : The numeric x & y values to offset floating subnavs by. */
	menuOffset : {x:0, y:0},
	/** private Array selectedIds : List of selected item ids. */
	selectedIds : [],
	/** private void initDefaultMenu : Initialize the current subnav menu at page load time. */
	initDefaultMenu : function() {
		var defaultMenu = null;
		for (var i=0; i<Navigation.selectedIds.length; i++) {
			var item = Navigation.getItem(Navigation.selectedIds[i]);
			if (item.isSection()) defaultMenu = item;
		}
		if (!defaultMenu) return;
		defaultMenu.initMenu();
		defaultMenu.initScreen();
	},
	/** public String getDisplayedSectionId : Get the id of the currently displayed subnav.
	  * @return ID of currently displayed subnav.
	  */
	getDisplayedSectionId : function() { return Navigation.displayedSectionId; },
	/** public NavigationItemVO getItem : Retrieve a NavigationItemVO wrapped around a
	  * nav item's HTML element. Items are initialized as requested (lazy loaded).
	  * @return Nav item wrapped in NavigationItemVO
	  */
	getItem : function(itemId) {
		if (!itemId || (itemId == "0")) return null;
		if (!Navigation.initializedItems[itemId]) Navigation.initializedItems[itemId] = new NavigationItemVO(itemId);
		return Navigation.initializedItems[itemId];
	},
	/** public Map getMenuOffset : Get the map of menu offset x,y values.
	  * @return Map of menu offset values
	  */
	getMenuOffset : function() { return Navigation.menuOffset; },
	/** public Array getSelectedIds : Get the list of currently selected navigation item ids.
	  * @return Array of selected item ids
	  */
	getSelectedIds : function() { return Navigation.selectedIds; },
	/** public String getSelectedIdAt : Get the currently selected item's id at a specific level.
	  * @param int level Desired level
	  * @return Id of selected item at specified level
	  */
	getSelectedIdAt : function(level) {
		if (level < Navigation.selectedIds.length) return Navigation.selectedIds[level];
		return null;
	},
	/** public void setDisplayedSectionId : Set the id of the currently displayed subnav.
	  * @param String displayedSectionId Displayed section id to store
	  */
	setDisplayedSectionId : function(displayedSectionId) { Navigation.displayedSectionId = displayedSectionId; },
	/** public void setMenuOffset : Set the map of menu offset x,y values.
	  * @param String menuOffset Offset values map to store
	  */
	setMenuOffset : function(menuOffset) { Navigation.menuOffset = menuOffset; },
	/** public void setSelectedIds : Set the array of currently selected navigation item ids.
	  * @param Array selectedIds Selected ids array to store
	  */
	setSelectedIds : function(selectedIds) { Navigation.selectedIds = selectedIds; },
	/** public void setSelectedIdAt : Set the selected id at the specified level
	  * @param int level Desired level
	  * @param String selectedId Id of selected item
	  */
	setSelectedIdAt : function(level, selectedId) { Navigation.selectedIds[level] = selectedId; }
};

/* Add a body onLoad listener, so if a section was selected it inits the subnav menu. */
attachEventListener(window, "load", Navigation.initDefaultMenu);

/** public class NavigationItemVO : Wraps around a navigation item's HTML element,
  * provides methods to extract meta information about each item.
  * @param String itemId id of the HTML element to wrap
  */
NavigationItemVO = function(itemId) {
	this.element = document.getElementById(itemId);
	this.menuInitialized = false;
	this.screenInitialized = false;
	if (!this.element) return null;
}
/** public HTMLElement getElement : Get the HTML element this instance wraps.
  * @return Nav item's HTML element
  */
NavigationItemVO.prototype.getElement = function() { return this.element; }
/** public String getId : Get the id of the HTML element.
  * @return Nav item's id
  */
NavigationItemVO.prototype.getId = function() { return this.element.getAttribute("id"); }
/** public Image getImage : Get the button image of the HTML element.
  * @return Nav item's button image
  */
NavigationItemVO.prototype.getImage = function() { return document.images[Navigation.IMAGE_PREFIX + this.getId()]; }
/** public int getLevel : Get the level of the HTML element.
  * @return Nav item's level
  */
NavigationItemVO.prototype.getLevel = function() { return parseInt(this.element.getAttribute("level")); }
/** public String getName : Get the name of the HTML element.
  * @return Nav item's name
  */
NavigationItemVO.prototype.getName = function() { return this.element.getAttribute("name"); }
/** public String getParentId : Get the id of the HTML element's parent, if any.
  * @return Nav item's parent's id
  */
NavigationItemVO.prototype.getParentId = function() { return this.element.getAttribute("parentId"); }
/** public String getUrl : Get the url a nav button forwards to, or null if a section.
  * @return Nav item's url
  */
NavigationItemVO.prototype.getUrl = function() {
	if (this.isSection()) return null;
	return ((new RegExp(/navForward\('[^\']*', ?'([^\']*)', ?'[^\']*'\)/).test(this.element.onclick)) ? RegExp.$1 : null);
}
/** public void hideMenu : Hide a section's subnav menu. */
NavigationItemVO.prototype.hideMenu = function() {
	if (!this.isSection()) return;
	var subnavMenu = document.getElementById(Navigation.SUBNAV_PREFIX + this.getId());
	if (subnavMenu) subnavMenu.className = Navigation.HIDE_CLASS;
	var subnavScreen = document.getElementById(Navigation.SUBNAV_PREFIX + this.getId() + Navigation.SCREEN_SUFFIX);
	if (subnavScreen) subnavScreen.className = Navigation.HIDE_CLASS;
}
/** private void initMenu : If the menuType is "float", move a subnav menu to the correct position. */
NavigationItemVO.prototype.initMenu = function() {
	var menu = document.getElementById(Navigation.SUBNAV_PREFIX + this.getId());
	this.menuInitialized = true;
	if (!menu || (menuType != "float")) return;
	// set z-index on subnav parent element, otherwise relative-positioned content in the layout shows through
	if (document.getElementById("subnavWrapper")) document.getElementById("subnavWrapper").style.zIndex = Navigation.FLOATING_SUBNAV_ZINDEX;
	else menu.offsetParent.style.zIndex = Navigation.FLOATING_SUBNAV_ZINDEX;
	// set menu position
	menu.style.position = "absolute";
	var offset = Navigation.getMenuOffset();
	menu.style.left = this.element.offsetLeft + ((offset.x) ? offset.x : 0) + "px";
	menu.style.top = this.element.offsetTop + ((offset.y) ? offset.y : 0) + "px";
}
/** private	 void initScreen : Move a subnav menu's backing iframe to the correct position. */
NavigationItemVO.prototype.initScreen = function() {
	var menu = document.getElementById(Navigation.SUBNAV_PREFIX + this.getId());
	if (!menu) return;
	var screen = document.getElementById(Navigation.SUBNAV_PREFIX + this.getId() + Navigation.SCREEN_SUFFIX);
	if (!screen) return;
	// true when menu is hidden, as in rollover menus. should be initted on first rollover instead.
	if (menu.className == Navigation.HIDE_CLASS) return;
	this.screenInitialized = true;
	screen.style.position = "absolute";
	screen.style.top = menu.style.top;
	screen.style.left = menu.style.left;
	screen.style.width = menu.offsetWidth;
	screen.style.height = menu.offsetHeight;
}
/** public boolean isOn : Item is currently "on", or selected.
  * @return true if item is "on", false if not.
  */
NavigationItemVO.prototype.isOn = function() { return (Navigation.getSelectedIdAt(this.getLevel()) == this.getId()) ? true : false; }
/** public boolean isOver : Item is currently "over".
  * @return true if item is "over", false if not.
  */
NavigationItemVO.prototype.isOver = function() { return (Navigation.getDisplayedSectionId() == this.getId()) ? true : false; }
/** public boolean isSection : Item is a section.
  * @return true if item is a section, false if not.
  */
NavigationItemVO.prototype.isSection = function() { return (this.element.getAttribute("isSection") == "true") ? true : false; }
/** public void on : Change a nav item's state to "on", applying classes, switching images, etc. */
NavigationItemVO.prototype.on = function() {
	var image = this.getImage();
	if (image) image.src = image.src.replace(Navigation.MO_IMAGE_RE, Navigation.LIVE_SUFFIX + Navigation.GIF_SUFFIX);
	var element = this.getElement();
	if (element) element.className = (this.getLevel() == 0) ? Navigation.MAINNAV_ITEM + Navigation.ON : Navigation.SUBNAV_ITEM + Navigation.ON;
}
/** public void out : Change a nav item's state to "out", applying classes, switching images, etc. */
NavigationItemVO.prototype.out = function() {
	var image = this.getImage();
	if (image) image.src = image.src.replace(Navigation.MO_IMAGE_RE, Navigation.OUT_SUFFIX + Navigation.GIF_SUFFIX);
	var element = this.getElement();
	if (element) element.className = (this.getLevel() == 0) ? Navigation.MAINNAV_ITEM: Navigation.SUBNAV_ITEM;
}
/** public void over : Change a nav item's state to "over", applying classes, switching images, etc. */
NavigationItemVO.prototype.over = function() {
	var image = this.getImage();
	if (image) image.src = image.src.replace(Navigation.OUT_IMAGE_RE, Navigation.MO_SUFFIX + Navigation.GIF_SUFFIX);
	var element = this.getElement();
	if (element) element.className = ((this.getLevel() == 0) ? Navigation.MAINNAV_ITEM : Navigation.SUBNAV_ITEM) + Navigation.OVER;
}
/** public void showMenu : Show a section's subnav menu, initting the menu and screen the first time. */
NavigationItemVO.prototype.showMenu = function() {
	var subnavMenu = document.getElementById(Navigation.SUBNAV_PREFIX + this.getId());
	if (subnavMenu) {
		if (!this.menuInitialized) this.initMenu();
		subnavMenu.className = Navigation.SHOW_CLASS;
	}
	var subnavScreen = document.getElementById(Navigation.SUBNAV_PREFIX + this.getId() + Navigation.SCREEN_SUFFIX);
	if (subnavScreen) {
		if (!this.screenInitialized) this.initScreen();
		subnavScreen.className = Navigation.SHOW_CLASS;
	}
}

/* Default navigation user actions. These functions do nothing but
 * implement the appropriate rollover affect. To apply specific
 * behavior (e.g. showing a subnav), include the appropriate nav
 * action class (e.g. showSubOnClickMain.js), make your own.
 */

/** public void itemOn : Only defined when not overridden by a nav action class.
  * Do nothing; items should not roll "on" by default to prevent
  * IE image loading issues between page loads.
  * @param Event e Click event triggering this function call
  * @param String itemId Id of nav item clicked
  */
if (!window.itemOn) {
	itemOn = function(e, itemId) {
		// cancel bubbling
		if (e) {
			e.cancelBubble = true;
			if (e.stopPropagation) {
				e.stopPropagation();
				e.preventDefault();
			}
		}
	}
}
/** public void itemOut : Only defined when not overridden by a nav action class.
  * Change the specified item's classes, images, etc. to the "out" state,
  * and remove the status text.
  * @param Event e Mouseout event triggering this function call
  * @param String itemId Id of nav item moused-out from
  */
if (!window.itemOut) {
	itemOut = function(e, itemId) {
		// cancel bubbling
		if (e) {
			e.cancelBubble = true;
			if (e.stopPropagation) {
				e.stopPropagation();
				e.preventDefault();
			}
		}
		// hide status text
		window.status = "";
		var item = Navigation.getItem(itemId);
		// document has not finished loading or bogus itemId
		if (!item) return;
		// change the classes, images, etc. for items not already "on"
		if (!item.isOn()) item.out();
	}
}
/** public void itemOver : Only defined when not overridden by a nav action class.
  * Change the specified item's classes, images, etc. to the "over" state,
  * and show the status text.
  * @param Event e Mouseover event triggering this function call
  * @param String itemId Id of nav item moused-over
  * @param String statusText Text to display in self.status
  */
if (!window.itemOver) {
	itemOver = function(e, itemId, statusText) {
		if (editMode) return;
		// cancel bubbling
		if (e) {
			e.cancelBubble = true;
			if (e.stopPropagation) {
				e.stopPropagation();
				e.preventDefault();
			}
		}
		// show status text
		window.status = (statusText) ? statusText : "";
		var item = Navigation.getItem(itemId);
		// document has not finished loading or bogus itemId
		if (!item) return;
		// change the classes, images, etc. for items not already "on"
		if (!item.isOn()) item.over();
	}
}

/* Default "other" navigation user actions. These functions do nothing.
 * Override in index.jsp to apply specific behavior.
 */
if (!window.otherMainNavClick) {
	otherMainNavClick = function() {}
}
if (!window.otherSubNavClick) {
	otherSubNavClick = function() {}
}


/** public void navForward : Called when a nav item is clicked on.
  * Forwards to the specified url, in the specified window.
  * Can be overridden if desired, for example if some extra action
  * is desired before page unload. 'itemId' param is passed in case
  * of this.
  * @param String itemId ID of nav item clicked on
  * @param String url URL to forward to
  * @param String target Target window
  */
navForward = function(itemId, url, target) {
	linkToPage(url, target);
}
