
var allBMenus = new Array();		// this is the only globally accessible variable for bmenu

// only function called from the DOM: initialized and assigns object definition to DOM object
// called on every mouseover, only initializes once per page load

function BMenu_SetCurrentElement(bmenuID, bmenu_id) {
	if ( !allBMenus[bmenuID] ) {
		allBMenus[bmenuID] = new BMenu(bmenuID);
	}
	allBMenus[bmenuID].bmenu_id = bmenu_id;
}

BMenu = function(DOM_ID) {
	// constructor variables
	this.bmenu_active = Array();
	this.bmenu_timeoutArray = Array();
	this.bmenu_current = 0;
	this.bmenu_last = 0;
	this.bmenu_id = String();
	
	// initialize DOM reference
	this.DOMElement = document.getElementById(DOM_ID);
	this.DOMElement.Menu = this;	// creates back reference to object callable through DOM

	// what's in a name?
	this.MenuName = DOM_ID;

	// assign events
	this.DOMElement.onmouseover = this.MenuRollover;
	this.DOMElement.onmouseout = this.MenuRollout;

	// this loads settings from PHP
	this.bmenu_settings = document.getElementById(this.MenuName + '_settings');
	if (this.bmenu_settings) {
		var customSettings = this.bmenu_settings.innerHTML;	// get settings string
		customSettingsArray = customSettings.split(";");	// split each key/value pair
		for(i in customSettingsArray) {	
			var customElement = customSettingsArray[i].split("=");	// split key from value
			if (customElement[0]) {	// only check for key (value might eval as "false")
				varName = 'this.bmenu_' + customElement[0];
				evalString = varName + ' = \"' + customElement[1] + '\";';
				eval(evalString);
				if (parseInt(eval(varName)) == eval(varName)) {		// if we have a number, data type must match
					eval(varName + ' = parseInt(' + varName + ');');
				}
			}
		}
	} else {
		// in case settings fail, assign default ones here.  BMenu will not work without these settings
		this.bmenu_arrangement = "horizontal";	// arrangement of root menu (changes location of first child dropdown)
		this.bmenu_keepHighlight = 1;		// when true, parent menus stay highlighted when rolling over children
		this.bmenu_timeoutDelay = 100;		// time in ms before rollout triggers a turn-off for dropdowns
		this.bmenu_debugMode = 0;		// boolean for debugging
		this.bmenu_menuWidth = 100;		// default width for vertical arrangement (must be defined for mozilla)
		this.bmenu_submenuWidth = 100;		// default width for dropdowns
		this.bmenu_dropdownSpacing = 0;		// default spacing between dropdowns
	}

	/*
	// styles
	this.Style = new Object();
	this.Style.menu_BorderWidth = 1;	// border width of main menu
	*/
	
	/*
	var test = "";
	for(i in this.bmenu_settings) {
		if (this.bmenu_settings[i] == "asdf") {
			test += i + "=" + this.bmenu_settings[i] + "\n";
		}
	}
	alert(test);
	*/

}

BMenu.prototype.MenuRollover = function() {
	
	if (this.Menu.bmenu_debugMode) this.Menu.MenuClearOutput();

	var thisParent = this.Menu.MenuGetParent(this.Menu.bmenu_id);

	if (this.Menu.bmenu_last) {
		
		// we skip the rollout sequence and immediately deactivate last element
		// unless the new element is a child of the last
		clearInterval(this.Menu.bmenu_timeoutArray[this.Menu.bmenu_last]);
		
		if (thisParent != this.Menu.bmenu_last) {
			this.Menu.MenuDeactivateElement(this.Menu.bmenu_last);
		} else if (thisParent != "" && !this.Menu.bmenu_keepHighlight) {
			// turn off parent class
			var myParent = document.getElementById(this.Menu.MenuName + thisParent);
			newClass = myParent.className.substr(0, myParent.className.lastIndexOf('_')) + '_off';
			this.Menu.MenuSetElementClass(myParent, newClass);
		}

	}

	// activate element
	if (this.Menu.bmenu_debugMode) this.Menu.MenuAddOutput('activate called from rollover()');
	this.Menu.MenuActivateElement(this.Menu.bmenu_id);
	
	// define the element locally
	var thisElement = document.getElementById(this.Menu.MenuName + this.Menu.bmenu_id);
	if (!thisElement) {
		if (this.Menu.bmenu_debugMode) this.Menu.MenuAddOutput('ERROR bmenu_rollover(): ' + this.Menu.bmenu_id + ' does not exist!');
	}
	// get new class name
	newClass = thisElement.className.substr(0, thisElement.className.lastIndexOf('_')) + '_on';
	this.Menu.MenuSetElementClass(thisElement, newClass);

	// set element as current...
	this.Menu.bmenu_current = this.Menu.bmenu_id;

	// show the child div
	this.Menu.MenuShowChild(this.Menu.bmenu_id);

	// activate all parents
	this.Menu.MenuActivateParents(this.Menu.bmenu_id);

	if (this.Menu.bmenu_last) {
		// get last parent
		var lastParent = this.Menu.MenuGetParent(this.Menu.bmenu_last);
		
		// tricky: we only deactivate parents if the following three cases fail:
		// 1) if last and current are siblings;
		// 2) if last's parent is current;
		// 3) last's parent's parent is current's parent (jumped to parent's sibling)
		// if any of these are true, we can maintain dropdown family tree.
		// if these fail, one of two things has happened:
		// 1) we've moved to another parent tree (i.e. a submenu to a different top-most parent), or
		// 2) we've moved too far from current element to maintain family tree (i.e. grandparent jump - unlikely in 1/10th of a second)
		// and we are forced to collapse everything from last element up to top-most parent

		if (lastParent == thisParent) { // sibling test
		} else if (lastParent == this.Menu.bmenu_id) { // jumped back to parent
		} else if (this.Menu.MenuGetParent(lastParent) == thisParent) { // jumped to a parent's sibling
			this.Menu.MenuDeactivateElement(lastParent);
		} else {
			if (this.Menu.bmenu_active[this.Menu.bmenu_last] == 0) {
				if (this.Menu.bmenu_debugMode) this.Menu.MenuAddOutput('deactivateParents called from rollover(' + this.Menu.bmenu_id + '), because bmenu_active[' + this.Menu.bmenu_last + '] = 0');
				this.Menu.MenuDeactivateParents(this.Menu.bmenu_last);
			}
		}
	}
	
	
	// ...and set as last
	this.Menu.bmenu_last = this.Menu.bmenu_id;


}

BMenu.prototype.MenuRollout = function() {
	if (this.Menu.bmenu_debugMode) this.Menu.MenuAddOutput('MenuRollout ' + this.Menu.bmenu_id);
	
	// toggle the item for deactivation
	this.Menu.bmenu_active[this.Menu.bmenu_id] = 0;
	
	// erase the current
	this.Menu.bmenu_current = 0;
	
	// begin timeout for rollout
	// setTimeout is external from object scope, have to redefine for MenuTimeout function
	this.Menu.bmenu_timeoutArray[this.Menu.bmenu_id] = setTimeout("allBMenus['" + this.Menu.MenuName + "'].MenuTimeout('" + this.Menu.MenuName + "')", this.Menu.bmenu_timeoutDelay);
}

BMenu.prototype.MenuTimeout = function(objRef) {

	// redefine BMenu:
	// var thisMenu = allBMenus[objRef];
	var thisMenu = this.DOMElement.Menu;
	// if (thisMenu.bmenu_debugMode) thisMenu.MenuAddOutput('BEGIN TIMEOUT ' + bmenu_id);
	
	for (i in thisMenu.bmenu_active) {
		
		if (thisMenu.bmenu_active[i] == 0) {

			thisMenu.bmenu_active[i] = 0;

			// deactive this element
			thisMenu.MenuDeactivateElement(i);

			if (thisMenu.bmenu_current == 0) {
				thisMenu.MenuDeactivateParents(i);
				// alert('no active element');
			}
			
		}

	}

	// clear the array
	thisMenu.bmenu_active = new Array();

}

BMenu.prototype.MenuActivateElement = function(this_bmenu_id) {

	// redefine object
	var thisMenu = this.DOMElement.Menu;

	// if (thisMenu.bmenu_debugMode) thisMenu.MenuAddOutput('Activating ' + bmenu_id);

	// set as active
	thisMenu.bmenu_active[this_bmenu_id] = 1;

	// turn off any timeout
	if (thisMenu.bmenu_timeoutArray[this_bmenu_id]) {
		clearInterval(thisMenu.bmenu_timeoutArray[this_bmenu_id]);
	}

}

BMenu.prototype.MenuDeactivateElement = function(this_bmenu_id) {

	// redefine object
	var thisMenu = this.DOMElement.Menu;

	// for (i in this) { alert(i + " = " + this[i]); }

	// if (thisMenu.bmenu_debugMode) thisMenu.MenuAddOutput('Deactivating ' + this_bmenu_id);

	// define the element locally
	var thisElement = document.getElementById(thisMenu.MenuName + this_bmenu_id);

	if (!thisElement) {
		if (thisMenu.bmenu_debugMode) thisMenu.MenuAddOutput('ERROR bmenu_deactivateElement(): ' + bmenu_id + ' does not exist!');
	}

	// turn element off
	newClass = thisElement.className.substr(0, thisElement.className.lastIndexOf('_')) + '_off';
	thisMenu.MenuSetElementClass(thisElement, newClass);

	// hide its child
	thisMenu.MenuHideChild(this_bmenu_id);

}


BMenu.prototype.MenuSetElementClass = function(thisElement, newClass) {

	if (!thisElement) {
		return;
	}

	// set element class
	thisElement.className = newClass;

}


BMenu.prototype.MenuHideChild = function(this_bmenu_id) {
	
	// redefine object
	var thisMenu = this.DOMElement.Menu;
	
	// get submenu, if one exists
	var thisSubmenu = document.getElementById(thisMenu.MenuName + '_div' + this_bmenu_id);

	if (thisSubmenu) {

		// assign style to the cell
		thisSubmenu.style.position = "absolute";
		thisSubmenu.style.display = "none";

	}

}


BMenu.prototype.MenuShowChild = function(this_bmenu_id) {

	// redefine object
	var thisMenu = this.DOMElement.Menu;

	// redefine element
	var thisElement = document.getElementById(thisMenu.MenuName + this_bmenu_id);
	
	// get submenu, if one exists
	var thisSubmenu = document.getElementById(thisMenu.MenuName + '_div' + this_bmenu_id);

	if (thisSubmenu) {

		// if (thisMenu.bmenu_debugMode) thisMenu.MenuAddOutput('Activating child bmenu_div' + bmenu_id);

		// first set the coords of this element
		thisX = parseInt(thisMenu.MenuGetCoord(thisElement, 'x'));
		thisY = parseInt(thisMenu.MenuGetCoord(thisElement, 'y'));
		var parentCount = thisMenu.MenuCountParents(this_bmenu_id);
		// CUSTOM: set menu coords here
		if (parentCount == 0) {
			// this is the first child
			if (thisMenu.bmenu_arrangement == "vertical") {
				finalX = thisX + parseInt(thisElement.offsetWidth) + thisMenu.bmenu_dropdownSpacing;
				finalY = thisY;
			} else {
				finalX = thisX;
				finalY = thisY + parseInt(thisElement.offsetHeight) + thisMenu.bmenu_dropdownSpacing;
			}
		} else {
			// this is a sub dropdown ("dropacross")
			finalX = thisX + parseInt(thisElement.offsetWidth) + thisMenu.bmenu_dropdownSpacing;
			finalY = thisY;
		}
		// assign to the cell
		thisSubmenu.style.left = finalX + "px";
		thisSubmenu.style.top = finalY + "px";
		thisSubmenu.style.position = "absolute";
		thisSubmenu.style.display = "inline";

	}

}

BMenu.prototype.MenuCountParents = function(this_bmenu_id) {
	var allParents = this_bmenu_id.split('_');
	var numParents = 0;
	for (i in allParents) {
		if (allParents[i] != "") {
			numParents++;
		}
	}
	numParents -= 1;
	return numParents;
}

BMenu.prototype.MenuGetCoord = function (thisObj, axis) {
	// set coord to zero (default offset is zero for any object)
	var thisCoord = 0;
	while (thisObj.offsetParent) {
		if (axis == "x") {
			thisCoord += parseInt(thisObj.offsetLeft);
		} else if (axis == "y") {
			thisCoord += parseInt(thisObj.offsetTop);
		}
		thisObj = thisObj.offsetParent;
	}
	return thisCoord;
}

BMenu.prototype.MenuActivateParents = function(this_bmenu_id) {

	// redefine object
	var thisMenu = this.DOMElement.Menu;

	// if (thisMenu.bmenu_debugMode) thisMenu.MenuAddOutput('(Activating parents of ' + bmenu_id + ':)');

	var bmenuParents = this_bmenu_id.split('_');
	var thisParent = "";
	for (i in bmenuParents) {
		if (bmenuParents[i] != "") {
			thisParent += '_' + bmenuParents[i];
			thisMenu.MenuActivateElement(thisParent);
		}
	}

}


BMenu.prototype.MenuDeactivateParents = function(this_bmenu_id) {
	
	// redefine object
	var thisMenu = this.DOMElement.Menu;

	var allIDs = this_bmenu_id.split("_"); /* for some reason split comes up with error if not on first line? */

	// if (thisMenu.bmenu_debugMode) thisMenu.MenuAddOutput('in deactivateParents(' + bmenu_id + ')...')

	var thisParent = thisMenu.MenuGetParent(this_bmenu_id);
	if (!thisParent) {
		// if (thisMenu.bmenu_debugMode) thisMenu.MenuAddOutput('&nbsp;&nbsp;&nbsp;no parent!');
		return;
	}

	if (thisMenu.bmenu_active[thisParent] == 0) {
		// if (thisMenu.bmenu_debugMode) thisMenu.MenuAddOutput('&nbsp;&nbsp;&nbsp;parent already inactive!');
		return;
	}

	var thisElement = "";
	var allParents = new Array();
	currentParent = thisMenu.MenuGetParent(thisMenu.bmenu_current);

	for (i in allIDs) {
		thisID = allIDs[i];
		if (thisID != "") {
			thisElement += "_" + thisID;
			if (thisElement != this_bmenu_id) {
				allParents.push(thisElement);
			}
		}
	}

	// start from current and work your way up
	allParents.reverse();

	for (i in allParents) {
		thisElement = allParents[i];
		if (thisMenu.bmenu_active[thisElement]) {
			// if (thisMenu.bmenu_debugMode) thisMenu.MenuAddOutput('deactivate called from deactivateParents()');
			thisMenu.MenuDeactivateElement(thisElement);
			thisMenu.bmenu_active[thisElement] = 0;
		}
	}

}

BMenu.prototype.MenuGetParent = function(this_bmenu_id) {
	if (!this_bmenu_id) {
		return;
	}
	allIds = this_bmenu_id.split("_");
	var constructParent = "";
	for (i in allIds) {
		if (allIds[i] != "") {
			if (allIds[parseInt(i)+1]) {
				constructParent += "_" + allIds[i];
			}
		}
	}
	return constructParent;
}

BMenu.prototype.MenuAddOutput = function(newText) {
	// redefine object
	var thisMenu = this.DOMElement.Menu;
	outputWindow = document.getElementById(thisMenu.MenuName + '_output').contentWindow;
	outputWindow.document.getElementById('output').innerHTML += "<br/>\n" + newText;
	outputWindow.scrollTo(0, 50000);
}

BMenu.prototype.MenuClearOutput = function() {
	// redefine object
	var thisMenu = this.DOMElement.Menu;
	outputWindow = document.getElementById(thisMenu.MenuName + '_output').contentWindow;
	outputWindow.document.getElementById('output').innerHTML = "";
}
