/**
* @fileoverview PopUp menu library
* @requires AtiraBase.js
*/


// Global constants
var atiraMenuImagePath = "images/";
var atiraMenuHideTime = 400;
var atiraMenuShowTime = 0;

var atiraMenuHandler = {
	idCounter		:	0,
	idPrefix		:	"atira-menu-object-",
	all				:	{},
	getId			:	function () { return this.idPrefix + this.idCounter++; },
	anyVisible		:	false,
	overMenuItem :
		function (oItem) {
			if (this.showTimeout != null) {
				window.clearTimeout(this.showTimeout);
			}
			if (this.hideTimeout != null) {
				window.clearTimeout(this.hideTimeout);
			}
			var jsItem = this.all[oItem.id];
			if (atiraMenuShowTime <= 0) {
				this._over(jsItem);
			} else {
				//this.showTimeout = window.setTimeout(function () { atiraMenuHandler._over(jsItem) ; }, atiraMenuShowTime);
				// I hate IE5.0 because the piece of shit crashes when using setTimeout with a function object
				this.showTimeout = window.setTimeout("atiraMenuHandler._over(atiraMenuHandler.all['" + jsItem.id + "'])", atiraMenuShowTime);
			}
	},
	outMenuItem :
		function (oItem) {
			if (this.showTimeout != null) {
				window.clearTimeout(this.showTimeout);
			}
			if (this.hideTimeout != null) {
				window.clearTimeout(this.hideTimeout);
			}
			var jsItem = this.all[oItem.id];
			if (atiraMenuHideTime <= 0) {
				this._out(jsItem);
			} else {
				//this.hideTimeout = window.setTimeout(function () { atiraMenuHandler._out(jsItem) ; }, atiraMenuHideTime);
				this.hideTimeout = window.setTimeout("atiraMenuHandler._out(atiraMenuHandler.all['" + jsItem.id + "'])", atiraMenuHideTime);
			}
		},
	blurMenu :
		function (oMenuItem) {
			window.setTimeout("atiraMenuHandler.all[\"" + oMenuItem.id + "\"].subMenu.hide();", atiraMenuHideTime);
		},
	_over :
		function (jsItem) {
			if (jsItem.subMenu) {
				jsItem.parentMenu.hideAllSubs();
				jsItem.subMenu.show();
			} else {
				jsItem.parentMenu.hideAllSubs();
			}
		},
	_out :
		function (jsItem) {
			// find top most menu
			var root = jsItem;
			var m;
			if (root instanceof AtiraMenuButton) {
				m = root.subMenu;
			} else {
				m = jsItem.parentMenu;
				while (m.parentMenu != null && !(m.parentMenu instanceof AtiraMenuBar)) {
					m = m.parentMenu;
				}
			}
			if (m != null) {	
				m.hide();
			}
		},
	hideMenu :
		function (menu) {
			if (this.showTimeout != null) {
				window.clearTimeout(this.showTimeout);
			}
			if (this.hideTimeout != null) {
				window.clearTimeout(this.hideTimeout);
			}
			//this.hideTimeout = window.setTimeout("atiraMenuHandler.all['" + menu.id + "'].hide()", atiraMenuHideTime);
		},
	showMenu :	
		function (menu, src, dir, event, showAtCursor) {
			if (this.showTimeout != null)
				window.clearTimeout(this.showTimeout);
			if (this.hideTimeout != null)
				window.clearTimeout(this.hideTimeout);
			if (arguments.length < 3)
				dir = "vertical";
			this.hideAllMenus();
			menu.show(src, dir, event, showAtCursor);
			this.anyVisible = true;
		},
	hideAllMenus :
		function (event) {
			for (prop in this.all) {
				try {
					this.all[prop].hide();
					//alert(this.all[prop]);
				}
				catch (ignore) {
					//alert(ignore);
				};
			}
			this.anyVisible = false;
		}
};




/**
 * Creates a new instance of a menu
 * @class Represents a pop-up menu
 * @contrsuctor
 */
function AtiraMenu() {
	this._menuItems	= [];
	this._subMenus	= [];
	this.id			= atiraMenuHandler.getId();
	this.top		= 0;
	this.left		= 0;
	this.shown		= false;
	this.parentMenu	= null;
	atiraMenuHandler.all[this.id] = this;
}

/** @private */
AtiraMenu.prototype.width = 100;
/** @private */
AtiraMenu.prototype.emptyText = "Empty";
/** @private */
AtiraMenu.prototype.useAutoPosition = true;


/**
 * Adds a new menuitem to the menu
 * @param {AtiraMenuItem} menuItem The AtiraMenuItem to add
 */
AtiraMenu.prototype.add = function (menuItem) {
	this._menuItems[this._menuItems.length] = menuItem;
	if (menuItem.subMenu) {
		this._subMenus[this._subMenus.length] = menuItem.subMenu;
		menuItem.subMenu.parentMenu = this;
	}
	
	menuItem.parentMenu = this;
};

/**
 * Counts the number of menuitems of the menu
 * @return {int} The number of menuitems of the menu
 */
AtiraMenu.prototype.getItemCount = function () {
	return this._menuItems.length;
}

/**
 * @private
 */
AtiraMenu.prototype.show = function (relObj, sDir, event ,showAtCursor) {
	
	// Call to calculate position
	if (showAtCursor) {
		var e = new AtiraEvent(event);
		this.left = e.mouseLeft();
		this.top = e.mouseTop();
	}
	else if (this.useAutoPosition) {
		this.position(relObj, sDir);
		if (event && false) {
			var e = new AtiraEvent(event);
			if (e.mouseLeft()-this.left>100) {
				this.left = e.mouseLeft();
			}
			if (e.mouseTop()-this.top>20) {
				this.top = e.mouseTop();
			}
		}
	}
	
	
	// Set top+left and show the menu
	var divElement = document.getElementById(this.id);
	divElement.style.left = isOpera() ? this.left : this.left + "px";
	divElement.style.top = isOpera() ? this.top : this.top + "px";
	divElement.style.visibility = "visible";
	
	// Mark as shown
	this.shown = true;
	
	// Show the parent menu if it has one
	if (this.parentMenu)
		this.parentMenu.show();
};

/**
 * @private
 */
AtiraMenu.prototype.hide = function () {
	this.hideAllSubs();
	var divElement = document.getElementById(this.id);
	divElement.style.left='0px';
	divElement.style.visibility = "hidden";
	this.shown = false;
};

/**
 * @private
 */
AtiraMenu.prototype.hideAllSubs = function () {
	for (var i = 0; i < this._subMenus.length; i++) {
		if (this._subMenus[i].shown)
			this._subMenus[i].hide();
	}
};

/**
 * Generates the HTML for the complete menu
 * @return {String} HTML of the menu as a string
 */
AtiraMenu.prototype.toString = function () {
	var top = this.top;
	var str = "<div id='" + this.id + "' class='atira-menu' style='" + 
		//"width:" + this.width + "px;" +
			(this.useAutoPosition ?
			"left:" + this.left + "px;" + "top:" + this.top + "px;" : "") +
	"'>";
	
	if (this._menuItems.length == 0) {
		str +=	"<span class='atira-menu-empty'>" + this.emptyText + "</span>";
	}
	else {
		//alert(this._menuItems.length);
		// loop through all menuItems
		for (var i = 0; i < this._menuItems.length; i++) {
			var mi = this._menuItems[i];
			str += mi.toString();
			if (!this.useAutoPosition) {
				if (mi.subMenu && !mi.subMenu.useAutoPosition)
					mi.subMenu.top = top;
				top += mi.height;
			}
		}

	}
	
	str += "</div>";

	for (var i = 0; i < this._subMenus.length; i++) {
		this._subMenus[i].left = this.left + this.width;
		str += this._subMenus[i];
	}
	
	return str;
};


AtiraMenu.prototype.build = function() {
	var holder = document.createElement('div');
    document.body.appendChild(holder);
    holder.innerHTML=this.toString();
}


////////////////////////////////////////////////////////////////////////
////                       AtiraMenuItem                             ////
////////////////////////////////////////////////////////////////////////

/**
 * Creates a new instance of a menu item
 * @class Represents an item in a menu
 * @param {String} text The text of the menu item
 * @param {String} href The link of the menu item
 * @param {String} toolTip The tool tip of the menu item
 * @param {AtiraMenu} subMenu A sub menu of the menuitem
 * @param {String} target The target of the link
 */
function AtiraMenuItem(text, href, toolTip, subMenu, target) {
	this.text = text || "Untitled";
	this.href = (href == null || href == "") ? "javascript:void(0)" : href;
	this.subMenu = subMenu;
	if (subMenu)
		subMenu.parentMenuItem = this;
	this.toolTip = toolTip;
	this.target = target;
	this.id = atiraMenuHandler.getId();
	atiraMenuHandler.all[this.id] = this;
}

/**
 * @private
 */
AtiraMenuItem.prototype.height = 18;

/**
 * @private
 */
AtiraMenuItem.prototype.toString = function() {
	return "<a id='" + this.id + "'" +
		" href=\"" + this.href + "\"" +
		" onmouseover='atiraMenuHandler.overMenuItem(this)'" +
		(this.toolTip ? " title=\"" + this.toolTip + "\"" : "") +
		(this.target ? " target=\"" + this.target + "\"" : "") +
		(this.subMenu ? " unselectable='on' tabindex='-1'" : "") +
		">" +
		(this.subMenu ? "<img class='arrow' src=\"" + atiraMenuImagePath + "arrow.right.png\">" : "") +
		this.text + "</a>";
} 




/**
 * Creates a new instance of a menu separator
 * @class Represents a separator in a menu
 * @constructor
 */
function AtiraMenuSeparator() {
	this.id = atiraMenuHandler.getId();
	atiraMenuHandler.all[this.id] = this;
};

/**
 * @private
 */
AtiraMenuSeparator.prototype.height = 6;

/**
 * @private
 */
AtiraMenuSeparator.prototype.toString = function () {
	return	"<div id='" + this.id + "' onmouseout='atiraMenuHandler.outMenuItem(this)'></div>";
};


/**
 * @private
 */
AtiraMenu.prototype.position = function (relEl, sDir) {
	var dir = sDir;
	// find parent item rectangle, piRect
	var piRect;
	if (!relEl) {
		var pi = this.parentMenuItem;
		if (!this.parentMenuItem) {
			return;
		}
		
		relEl = document.getElementById(pi.id);
		if (dir == null) {
			dir = "horizontal";//"vertical";
		}
		piRect = getOuterRect(relEl);
	}
	else if (relEl.left != null && relEl.top != null && relEl.width != null && relEl.height != null) {	// got a rect
		piRect = relEl;
	} else {
		piRect = getOuterRect(relEl);
	}
	
	var menuEl = document.getElementById(this.id);
	var menuRect = getOuterRect(menuEl);
	var docRect = getDocumentRect();
	var scrollPos = getScrollPos();
	var pMenu = this.parentMenu;
	
	if (dir == "vertical") {
		if (piRect.left + menuRect.width - scrollPos.left <= docRect.width)
			this.left = piRect.left;
		else if (docRect.width >= menuRect.width)
			this.left = docRect.width + scrollPos.left - menuRect.width - 20;
		else
			this.left = scrollPos.left;
			
		if (piRect.top + piRect.height + menuRect.height <= docRect.height + scrollPos.top)
			this.top = piRect.top + piRect.height;
		else if (piRect.top - menuRect.height >= scrollPos.top)
			this.top = piRect.top - menuRect.height;
		else if (docRect.height >= menuRect.height)
			this.top = docRect.height + scrollPos.top - menuRect.height;
		else
			this.top = scrollPos.top;
	}
	else {
		if (piRect.top + menuRect.height <= docRect.height + scrollPos.top)
			this.top = piRect.top;
		else if (piRect.top + piRect.height - menuRect.height >= 0)
			this.top = piRect.top + piRect.height - menuRect.height;
		else if (docRect.height >= menuRect.height)
			this.top = docRect.height + scrollPos.top - menuRect.height;
		else
			this.top = scrollPos.top;
		
		if (piRect.left + piRect.width + menuRect.width <= docRect.width + scrollPos.left)
			this.left = piRect.left + piRect.width + getDisplayStyleInt(menuEl,'padding-top');
		else if (piRect.left - menuRect.width >= 0)
			this.left = piRect.left - menuRect.width;
		else if (docRect.width >= menuRect.width)
			this.left = docRect.width  + scrollPos.left - menuRect.width;
		else
			this.left = scrollPos.left;
	}
};



////////////////////////////////////////////////////////////////////////////////
//                          AtiraMenuAttacher                                  //
////////////////////////////////////////////////////////////////////////////////

/**
 * @class Static class with methods to attach menus to elements
 */
function AtiraMenuAttacher() {
}

/**
 * Attaches a menu to an element - to be shown when clicked
 * @param {String} objId The id of the element the menu should be attached to
 * @param {AtiraMenu} menu The menu to be attached
 * @param {boolean} showAtCursor Sets whether the menu should appear at the cursor
 */
AtiraMenuAttacher.attachAsClickMenu = function(objId,menu,showAtCursor) {
    var obj = document.getElementById(objId);
    obj.onclick = AtiraMenuAttacher.clickHandler;
    obj.onblur = AtiraMenuAttacher.menuHider;
	obj.atiraMenuShowAtCursor = showAtCursor;
    obj.atiraMenu = menu;
}

/**
 * Attaches a menu to an element - to be shown when right clicked
 * @param {String} objId The id of the element the menu should be attached to
 * @param {AtiraMenu} menu The menu to be attached
 * @param {boolean} showAtCursor Sets whether the menu should appear at the cursor
 */
AtiraMenuAttacher.attachAsContextMenu = function(objId,menu,showAtCursor) {
    var obj = document.getElementById(objId);
    obj.oncontextmenu = AtiraMenuAttacher.contextHandler;
    obj.onblur=AtiraMenuAttacher.menuHider;
	obj.atiraMenuShowAtCursor = showAtCursor;
    obj.atiraMenu = menu;
}

/**
 * @private
 */
AtiraMenuAttacher.contextHandler = function(event) {
	if (this.atiraMenuWillShowMenu) {
		this.atiraMenuWillShowMenu();
	}
    atiraMenuHandler.showMenu(this.atiraMenu, this, 'vertical', event,this.atiraMenuShowAtCursor);
    return false;
}

/**
 * @private
 */
AtiraMenuAttacher.clickHandler = function(event) {
    atiraMenuHandler.showMenu(this.atiraMenu, this, 'vertical', event,this.atiraMenuShowAtCursor);
	stopEventPropagation(event);
    return false;
}

/**
 * @private
 */
AtiraMenuAttacher.menuHider = function() {
    atiraMenuHandler.hideMenu(this.atiraMenu);
}

// Hide all windows on document click
document.onclick = function(event) {atiraMenuHandler.hideAllMenus(event)};