// className functions
// Dean Edwards 2004.03.29
function addClass(element, className) {
	if (!hasClass(element, className)) element.className += " " + className;
};

function removeClass(element, className) {
	element.className = element.className.replace(new RegExp("\\b\\s*" +
className + "\\b", "g"), "");
};

function hasClass(element, className) {
	return (new RegExp("\\b" + className + "\\b")).test(element.className);
}

function List()
{
	this.a = new Array();
	this.size = 0;
	this.add = function(o)
	{
		this.a[this.size++] = o;
		return true;
	}

	this.getList = function()
	{
		return this.a;
	}

	this.remove = function(o)
	{
		for (x in a)
		{
			if (a[x] == o)
			{
				a[x] = null;
				return o;
			}
		}
	}

}

function Stack()
{
	this.stack = new Array();
	this.top = 0;
	this.push = function(a)
	{
		debugStackPush(a);
		this.stack[this.top++] = a;
		//this.draw();
		return;
	}
	this.pop = function()
	{
		a = (this.top > 0)?this.stack[--this.top]:-1;
		//this.draw();
		debugStackPop(a);
		return a;
	}
}

function areSiblings(navItemA, navItemB)
{
	if (navItemA.parentNavItem == navItemB.parentNavItem && navItemA != navItemB)
	{
		if (IS_DEBUG)debug('siblings: ' + navItemA.li.id + ' :: ' + navItemB.li.id);
		return true;
	}
	else
	{
		return false;
	}
}

function cleanStack(stack)
{
	if (IS_DEBUG)debug('cleaning stack.');

	var item = stack.pop();
	while (item != -1)
	{
		if (item != null) item.mouseout("clean stack");
		item = stack.pop();
	}
}

function isSame(navItem, stackItem)
{
	if (navItem == null) return false;
	else if (stackItem == null || stackItem == -1) return false;
	else if (navItem != stackItem) return false;
	else if (navItem == stackItem) return true;
	else alert("Stack isSame exception.");
}

// find parent and fire its event of the same type
function onFireParent(myEvent)
{ // can't call ele fireEvent in Firefox 1.5
	var e = new xEvent(myEvent);
	if (IS_DEBUG)debug("<b>firing parent for tag:</b> " + e.target.tagName);
	var li = findAncestor(e.target.parentNode, "LI");

	if (e.type == "mouseover")
	{
		if (IS_DEBUG)debug("direct call to parent mouseOver handler for: " + li.id);
		onNavItemOver(null, li);
	}
	else if (e.type == "mouseout")
	{ // workingHere:not seeing mouseOut in logger, but 2x mouseOver. Leads to prob when 2_b_1 --> 2_b in IE because they aren't touching.
		if (IS_DEBUG)debug("direct call to parent mouseOut handler.");
		onNavItemOut(null, li);
	}
	else
	{
		alert("Trying to fire parent, but encountered unsupported event type: " + e.type);
	}

	return;
	// removeMe

	/*
	var eventType = null;

	//debug(e.target.tagName + " firing " + e.type + " parent: " + parent.tagName + ":" + parent.id);

	if(e.addEventListener) {
	    eventType = e.type; // Mozilla
	} else if(e.attachEvent) {
	    eventType = "on" + e.type; // don't know when this is true
	} else {
	    eventType = "on" + e.type; // IE
	}

	parent.fireEvent(eventType);
    */
}

function findAncestor(ele, tagName, loopCount)
{
	if (loopCount != null) loopCount++; // removeMe: all this loop stuff - it was for debugging.
	else loopCount = 0;

	//alert("loop count: " + loopCount);

	if (ele.tagName != tagName)
	{
		if (IS_DEBUG)debug("Not find LI for child: " + tagName);
		return findAncestor(ele.parentNode, tagName, loopCount);
	}
	else
	{
		if (IS_DEBUG)debug("Found LI for child: " + tagName);
		return ele;
	}
}

function findTopLevelItem(eDescendant)
{
	var nav = NAVMASTERS.getNavMaster(eDescendant);
	var item = nav.getItem(findAncestor(eDescendant, "LI"));
	return item.getTopLevelItem(item);
}

function handleIePxQuirk()
{
	if (window.ActiveXObject)
	{
		var tr = document.getElementById("ofxAccordionRow");
		tr.style.position = "relative";

		var td = document.getElementById("ofxAccordionCell");
		td.style.position = "absolute";

		var spacerCell = document.createElement("TD");
		spacerCell.rowSpan = "3";
		spacerCell.className = "ofGridWidth3Toc";
		tr.insertAdjacentElement("afterBegin", spacerCell);

		setTimeout(bogusRemoveClass, 50);
		// For some reason, in IE, removing a non-existent class once will reset/close the accordion and fix that 1px gap
	}
}

function bogusRemoveClass()
{
	ele = document.getElementById("FixedIncome");
	removeClass(ele, "xxx");
}

/**
 * HTML Navbar
 * for use with UL/LI-based markup
 * @date: February 9, 2006
 * @author: Brian Willy (a348146), Fidelity Investments
 *
 * @depends: x_event.js, x_core.js(?), ofClassFunctions.js, ofNavOop.js
 */

// Note: to use x-browser, event names do not have the prefix "on"
// caller lives in ofNavOop.js

function attachEventHandlersItem(navItem)
{
	var e = navItem.li;

	//xAddEventListener(e, 'click', onNavItemClick, false);
	xAddEventListener(e, 'mouseover', onNavItemOver, false);
	xAddEventListener(e, 'mouseout', onNavItemOut, false);
}

// ------------------------------------------------------------------

function onNavItemClick(myEvent)
{
	alert("click.");
}

/** Called either by browser event, or directly by supporting code.
 In the latter instance, it is because Firefox will not/cannot fire
 a native LI event from within the supporting code when the A has
 the same event.
 */
function onNavItemOver(myEvent, altDirectCallTarget)
{
	if (myEvent != null && altDirectCallTarget != null) alert("Bad call to onNavItemOut. Both params were defined");

	var eventTarget;

	if (altDirectCallTarget != null)
	{
		eventTarget = altDirectCallTarget;
		if (IS_DEBUG)debug("over LI via child A: " + eventTarget.id);
	}
	else
	{
		// standard event
		var ev = new xEvent(myEvent);
		if (ev.target.tagName != "LI")
		{
			//debug("over event is not an LI");
			return false;
			// nested tags such as A and P fire this event // todo: as of 4/25/06, only A's are registered to fire parent Item
		}

		if (IS_DEBUG)debug('native over LI: ' + ev.target.id);


		eventTarget = ev.target;
	}

	if (IS_DEBUG) debugSetColor('green');

	try
	{
		var navItem = NAVMASTERS.getNavMaster(eventTarget).getItem(eventTarget);
		navItem.setMousingOver();
		navItem.getMasterNav().setMousingOver();
		// todo: create onNavItemOverExtension method for developers to extend behavior
	}
	catch(e)
	{
		alert("onNavItemOver error: " + e.message);
	}
}

function onNavItemOut(myEvent, altDirectCallTarget)
{
	if (myEvent != null && altDirectCallTarget != null) alert("Bad call to onNavItemOut. Both params were defined");

	var eventTarget;

	if (altDirectCallTarget != null)
	{
		eventTarget = altDirectCallTarget;
		if (IS_DEBUG)debug("native out LI via child A: " + eventTarget.id);
	}
	else
	{
		var ev = new xEvent(myEvent);
		if (ev.target.tagName != "LI") return false; // nested tags such as A and P fire this event

		if (IS_DEBUG)debug('native out LI: ' + ev.target.id);

		eventTarget = ev.target;
	}

	if (IS_DEBUG) debugSetColor('red');

	try
	{
		var navItem = NAVMASTERS.getNavMaster(eventTarget).getItem(eventTarget);
		navItem.setMousingOut();
		navItem.getMasterNav().setMousingOut();
	}
	catch(e)
	{
		alert("onNavItemOut error: " + e.message);
	}
}

/**
 Created by: Michael Synovic
 on: 01/12/2003

 This is a Javascript implementation of the Java Hashtable object.
 Copyright (C) 2003  Michael Synovic

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

 Contructor(s):
 Hashtable()
 Creates a new, empty hashtable

 Method(s):
 void clear()
 Clears this hashtable so that it contains no keys.
 boolean containsKey(String key)
 Tests if the specified object is a key in this hashtable.
 boolean containsValue(Object value)
 Returns true if this Hashtable maps one or more keys to this value.
 Object get(String key)
 Returns the value to which the specified key is mapped in this hashtable.
 boolean isEmpty()
 Tests if this hashtable maps no keys to values.
 Array keys()
 Returns an array of the keys in this hashtable.
 void put(String key, Object value)
 Maps the specified key to the specified value in this hashtable. A NullPointerException is thrown is the key or value is null.
 Object remove(String key)
 Removes the key (and its corresponding value) from this hashtable. Returns the value of the key that was removed
 int size()
 Returns the number of keys in this hashtable.
 String toString()
 Returns a string representation of this Hashtable object in the form of a set of entries, enclosed in braces and separated by the ASCII characters ", " (comma and space).
 Array values()
 Returns a array view of the values contained in this Hashtable.
 Array entrySet()
 Returns a reference to the internal array that stores the data. The Set is backed by the Hashtable, so changes to the Hashtable are reflected in the Set, and vice-versa.

 */
function Hashtable()
{
	this.hashtable = new Array();
}

/* privileged functions */

Hashtable.prototype.clear = function()
{
	this.hashtable = new Array();
}
Hashtable.prototype.containsKey = function(key)
{
	var exists = false;
	for (var i in this.hashtable)
	{
		if (i == key && this.hashtable[i] != null)
		{
			exists = true;
			break;
		}
	}
	return exists;
}
Hashtable.prototype.containsValue = function(value)
{
	var contains = false;
	if (value != null)
	{
		for (var i in this.hashtable)
		{
			if (this.hashtable[i] == value)
			{
				contains = true;
				break;
			}
		}
	}
	return contains;
}
Hashtable.prototype.get = function(key)
{
	return this.hashtable[key];
}
Hashtable.prototype.isEmpty = function()
{
	return (parseInt(this.size()) == 0) ? true : false;
}
Hashtable.prototype.keys = function()
{
	var keys = new Array();
	for (var i in this.hashtable)
	{
		if (this.hashtable[i] != null)
			keys.push(i);
	}
	return keys;
}
Hashtable.prototype.put = function(key, value)
{
	if (key == null || value == null)
	{
		throw "NullPointerException {" + key + "},{" + value + "}";
	}
	else
	{
		this.hashtable[key] = value;
	}
}
Hashtable.prototype.remove = function(key)
{
	var rtn = this.hashtable[key];
	this.hashtable[key] = null;
	return rtn;
}
Hashtable.prototype.size = function()
{
	var size = 0;
	for (var i in this.hashtable)
	{
		if (this.hashtable[i] != null)
			size ++;
	}
	return size;
}
Hashtable.prototype.toString = function()
{
	var result = "";
	for (var i in this.hashtable)
	{
		if (this.hashtable[i] != null)
			result += "{" + i + "},{" + this.hashtable[i] + "}\n";
	}
	return result;
}
Hashtable.prototype.values = function()
{
	var values = new Array();
	for (var i in this.hashtable)
	{
		if (this.hashtable[i] != null)
			values.push(this.hashtable[i]);
	}
	return values;
}
Hashtable.prototype.entrySet = function()
{
	return this.hashtable;
}

