/**
 * @author Mark Cassar
 * @version 1.0.0 
 * @lastmodified 27/10/07
 */

if (!com) var com = new Object();
if (!com.cs) com.cs = new Object();
if (!com.cs.ui) com.cs.ui = new Object();


//STATICS

/**
 * This will create a popup menu that will open to the left or right.
 * 
 * To use this class, you have to define a series of div tags with the menu structure.  The structure is as follows:
 * 
 * <div id="mainmenu">
	 * <div>Element 1</div>
	 * <div>Element 2</div>
	 * <div>	  		
	 * 		<div>Element with Submenu</div>
	 * 		<div>
	 * 			<div>Submenu element 1</div>
	 * 			<div>Submenu element 2</div>
	 * 		<div>
	 * 		
	 * </div>
	 * <div>Element 3</div>
	 * <div>Element 4</div>
 * </div>
 * 
 * Then pass the div as a parameter to the com.cs.ui.PopUpMenu class
 * 
 * EVENTS:
 * -------
 * 
 * onMenuItemOpen(popUpMenu:com.cs.ui.PopupMenu, div:HTMLDivElement);
 * onMenuItemClose(popUpMenu:com.cs.ui.PopupMenu, div:HTMLDivElement);
 * onMenuClose(popUpMenu:com.cs.ui.PopupMenu);
 * 
 * You will have 3 events with this popup menu.  onMenuItemOpen will trigger whenever a new menu is opened.  
 * It will contain this popup menu and the the div of the opened menu as a parameter.
 * 
 * The other event is onMenuItemClose which is triggered whenver the menu is closed. 
 * * The div element will be
 * hidden with property div.style.display = 'none'
 * 
 * onMenuClose will trigger when the entire menu has closed and mouse has moved out from the menu
 * 
 * @param {Object} div div of main menu
 * @param {Object} openLeft Wheter to open left or right. Boolean.
 * @param {Object} closeTimeout Amount in ms to close popup menu after mouse has rolled out of the menu
 */
com.cs.ui.PopUpMenu = function(div, closeTimeout, openLeft) {
	/**
	 * PUBLIC PROPERTIES*/
	this.openLeft = openLeft;
	this.closeTimeout = closeTimeout || 50;
	this.enabled = true;
	
	/** PUBLIC EVENTS */
	this.onMenuItemOpen = function(popUpMenu, div) {};
	this.onMenuItemClose = function(popUpMenu, div) {};
	this.onMenuClose = function(popUpMenu) {};
	
	if (!div) {
		alert("ERROR: com.cs.ui.PopupMenu > Please pass root div element for menu.");
		return;
	}
	if (div.tagName.toLowerCase() != "div") {
		alert("ERROR: com.cs.ui.PopupMenu > Root node must be a div element");
	}
	
	

	this._callOutTimeoutID;
	this._callOut = false; 
	this._rootMenuLevel = null;
	var scope = this;
	
	this.mouseOverDiv = function(menuItem) {
		if (scope.enabled) {
			clearTimeout(scope._callOutTimeoutID);
			menuItem.menuLevel.hideSubMenu();// hide any previous opened submenus of this level
			if (menuItem.subMenu) {
				menuItem.subMenu.show();
			}
		}
	}	
	/**
	 * This function is called whenever mouse is moved out of the menu
	 * @param {Object} menuItem
	 */
	this.mouseOutDiv = function(menuItem) {	
		//if (scope.enabled) {
			//This timeout is there since when a div calls an onout event, if the mouse is on another div, the other div will call the on in event
			//In that case, we don't want the on out to clear the menu.  The timeout makes sure that the mouse didnt stop on another div in the menu
			clearTimeout(scope._callOutTimeoutID);
			scope._callOutTimeoutID = setTimeout(scope.triggerOut,scope.closeTimeout);
		//}
	}
	this.triggerOut = function() {
		scope._rootMenuLevel.hideSubMenu();
		
		if (scope.onMenuClose) {
			scope.onMenuClose(scope);
		}
	}
	this.init = function() {
	
		var prevDisplay = div.style.display;
		scope._rootMenuLevel = new com.cs.ui.PopUpMenu.MenuLevel(div, null, null, this);
		div.style.display = prevDisplay;
	}
	this.init();
	
	
}
/**
 * This will check whether a particular div contains a sub menu or not.
 * @param {Object} div Object with two properties divTitle and divSubMenu.
 */
com.cs.ui.PopUpMenu.getDivs = function(div) {

	var obj = new Object();
	
	for (var i=0;i<div.childNodes.length;i++)
	{
		var node = div.childNodes[i];
	
		if (node.tagName && node.tagName.toLowerCase() == "div") {
			if (!obj.divTitle) {
				obj.divTitle = node;
			}
			else {
				obj.divSubMenu = node;
				break;
			}
		}
	}
	
	if (!obj.divTitle && !obj.divSubMenu) {
		return null;
	}
	else {
		if (!obj.divTitle || !obj.divSubMenu) {
			var errMsg = "Error: com.cs.ui.PopUpMenu\n\n";
			errMsg += "There is an error in the structure of one of the submenus.\n";
			errMsg += "You need to have the following structure for a submenu:\n";
			errMsg += "<div>\n\t<div>\n\t\tTITLE HERE\n\t</div>\n\t<div {MAIN MENU DIV}>\n\t</div>\n<div>";
			errMsg += "-----------------------------\n";
			errMsg += "Error found in the following div HTML code:\n";
			errMsg += divItem.innerHTML;
			alert(errMsg);
		}
		else {
			return obj;
		}
	}	
}

/**
 * This will create a level in the popup menu
 * @param {Object} divLevel The div element of the level which contains the items
 * @param {Object} parentLevel Parent level of this level
 * @param {Object} openOnMenuItem The item which will open this menu
 * @param {Object} popUpMenu The popup menu reference
 */
com.cs.ui.PopUpMenu.MenuLevel = function(divLevel, parentLevel, openOnMenuItem, popUpMenu) {
	this._openOnMenuItem = openOnMenuItem;
	this._parentLevel = parentLevel;
	this._popUpMenu = popUpMenu;
	this._menuItems = new Array();

	this._div = divLevel;
	this._divs = new Array();
	
	// PUBLIC PROPERTIES
	
	this.div = this._div;
	this.menuItems = this._menuItems;
	
	
	var scope = this;
	//This is so that submenus will not occupy space (width) within this level
	this._makeSubMenusAbsolute = function () {
		for (var i=0;i<scope._div.childNodes.length;i++) { 
			var node = scope._div.childNodes[i];
			if (node.tagName && node.tagName.toLowerCase() == "div") {
				var divItem = node;
				scope._divs.push(divItem);

				var objInnerDivs = com.cs.ui.PopUpMenu.getDivs(divItem);
				if (objInnerDivs) {
					// this div has a submen
					divItem.style.position = "relative";
					objInnerDivs.divSubMenu.style.position = "absolute";
				}
				
				
			}
		}
	}
	
	this._parseChildDivs = function() {
		for (var i=0;i<scope._divs.length;i++) {
			var div = scope._divs[i];
			scope._menuItems.push(new com.cs.ui.PopUpMenu.MenuItem(div,this,popUpMenu));		
		}
	}
	
	this.hideSubMenu = function() { // this will hide the opened child level
		if (scope.currOpenedLevel) {
			scope.currOpenedLevel.hide();
			scope.currOpenedLevel = null;
		}
	}
	this.show = function() {	
		scope._openOnMenuItem.positionSubMenu(); //Reposition the menu to the actual plaace
		scope._parentLevel.currOpenedLevel = scope;
		scope._div.style.display = "";
		if (scope._popUpMenu.onMenuItemOpen) {
			scope._popUpMenu.onMenuItemOpen(scope._popUpMenu,scope._div);
		}
	}
	this.hide = function() {
		scope.hideSubMenu(); // in case you have a submenu open
		scope._div.style.display = "none";
		if (scope._popUpMenu.onMenuItemClose) {
			scope._popUpMenu.onMenuItemClose(scope._popUpMenu,scope._div);
		}
	}
	
	this.init = function() {
		scope._makeSubMenusAbsolute();
		scope._parseChildDivs();
		scope.hide();
	}
	this.init();
	
	
}

/**
 * This is the item in the menu
 * @param {Object} divItem div element of item
 * @param {Object} menuLevel The level with which it is assigned to
 * @param {Object} popUpMenu The popup menu
 */
com.cs.ui.PopUpMenu.MenuItem = function(divItem, menuLevel, popUpMenu) {
	
	this._div = null;
	this._menuLevel = menuLevel;
	this._popUpMenu = popUpMenu;
	this._subMenu = null;
	
	var scope = this;
	
	this._initSubmenu = function() {
		divItem.style.position = "relative";
		scope.positionSubMenu();
		
	}	
	this.positionSubMenu = function() {
		if (scope._subMenu) {
			var div = scope._subMenu.div;
			var x = divItem.offsetWidth;

			if (scope._popUpMenu.openLeft) x = -x;
			div.style.left = x + "px";
			div.style.top = "0px";
		}
	}
	
	this._initHandlers = function() {
		
		scope._div.onmouseover = function () {			
			scope._popUpMenu.mouseOverDiv(scope);
		}
		scope._div.onmouseout = function() {
			scope._popUpMenu.mouseOutDiv(scope);
		}
	}
	
	this.init = function() {
		var objDivs = com.cs.ui.PopUpMenu.getDivs(divItem);
		if (!objDivs) {		
			// no sub menu
			scope._div = divItem;
		}
		else {				
			scope._div = objDivs.divTitle;
			scope._subMenu = new com.cs.ui.PopUpMenu.MenuLevel(objDivs.divSubMenu, menuLevel, scope, popUpMenu);
			scope._initSubmenu();		
		}
		scope._initHandlers();
	}
	this.init();
	
	/* PUBLIC PROPERTIES */
	this.subMenu = this._subMenu;
	this.menuLevel = this._menuLevel;
}
