// ContextMenu class
function ContextMenu(/*string*/ thisObjID, xmlMenuUrl, xsltMenuUrl, imagesFolder, /*milliseconds*/ hideTimeout, stylesheetPath /*=null*/)
{
	if(thisObjID == null)
	{alert("thisObjID is null"); return;}
	this.thisObjID = thisObjID;

	this.xslDocMenu = new ActiveXObject("MSXML2.DOMDocument.3.0");
	this.xslDocMenu.async = false;
	this.xslDocMenu.load(xsltMenuUrl);
	if(this.xslDocMenu.documentElement == null)
	{ alert("Failed to load xslt menu document"); return; }
	
	var sheet = this.xslDocMenu.documentElement.selectSingleNode("/xsl:stylesheet");
	sheet.selectSingleNode("xsl:param[@name='menu_obj_id']").text = this.thisObjID;
	sheet.selectSingleNode("xsl:param[@name='images_folder']").text = imagesFolder;
	if(stylesheetPath!=null)
		sheet.selectSingleNode("xsl:param[@name='stylesheet']").text = stylesheetPath;
	
	this.hideTimeout = (hideTimeout==null) ? 3000 : hideTimeout;
		
	this.shadowLength = this.IsMSIE5() ? 0 : 4; // for correct shadow length calculation in IE 5.0. Shadow DXImageTransform not supported

	this.aHideCallback = new Array();

	if(xmlMenuUrl!=null)
	{
		this.xmlDocMenu = new ActiveXObject("MSXML2.DOMDocument.3.0");
		this.xmlDocMenu.async = false;
		this.xmlDocMenu.load(xmlMenuUrl);
		if(this.xmlDocMenu.documentElement == null)
		{alert("Failed to load xml menu document"); return; }
		
		this.SetXmlDoc(this.xmlDocMenu);
	}
}
ContextMenu.prototype.GetXmlDoc = function()
{
	return this.xmlDocMenu;
}
ContextMenu.prototype.SetXmlDoc = function(xmlDoc)
{
	this.xmlDocMenu = xmlDoc;
	
	//generate menu IDs if not specified
	var nodesMenus = this.xmlDocMenu.selectNodes("//Menu");
	var id=0;
	for(var i=0; i<nodesMenus.length; i++)
	{
		if(nodesMenus[i].selectSingleNode("@ID")==null)
		{
			var nodeID = this.xmlDocMenu.createAttribute("ID");
			nodesMenus[i].attributes.setNamedItem(nodeID);
			
			// create unique id
			while(this.xmlDocMenu.selectSingleNode("//Menu[@ID='" + id + "']")!=null)
				id++;
			nodeID.text = id;
			id++;
		}
	}

	// create frames
	var nodesMenus = this.xmlDocMenu.selectNodes("//Menu[Menu]");
	var framesHTML = "";
	for(var i=0; i<nodesMenus.length; i++)
	{
		var id = nodesMenus[i].selectSingleNode("@ID").text;
//		frame = window.document.createElement("IFRAME"); // does not work in IE 5.0
		framesHTML += "<IFRAME"
		+ " id='" + this.thisObjID + "_" + id + "'"
		+ " frameBorder=0";
		+ " src='/MCMS/CMS/WAE/SSLStub.htm'";
		framesHTML += " style='Z-INDEX: " + (1000 + i) + "; POSITION: absolute; VISIBILITY: hidden; filter: progid:DXImageTransform.Microsoft.Shadow(color=gray, strength=" + this.shadowLength + ", direction=135);'"
		+ "></IFRAME>";
	}
	this.attachObj = window.document.createElement("SPAN");
	this.attachObj.innerHTML = framesHTML;
}
ContextMenu.prototype.RegisterHideCallback = function(func)
{
	this.aHideCallback[this.aHideCallback.length] = func;
}
ContextMenu.prototype.SetParent = function(objParent)
{
	this.objParent = objParent;
	objParent.appendChild(this.attachObj);
}
ContextMenu.prototype.SetDisabledCommandsInvisible = function(/*bool*/ invisible, menuID, accessLevel)
{
	if(this.xmlDocMenu == null)
	{alert("Failed to load xml menu document"); return;}

	accessLevel = parseInt(accessLevel.toString());

	var nodesCommadIDs = this.xmlDocMenu.selectNodes("//Menu[@ID='" + menuID + "']//Menu/@CommandID");
	for(var i=0; i<nodesCommadIDs.length; i++)
	{
		var commandID = nodesCommadIDs[i].text;
		var nodePermissionsMask = this.xmlDocMenu.selectSingleNode("//Command[@ID='" + commandID + "']/@PermissionsMask");
		if(nodePermissionsMask!=null)
			if( (parseInt(nodePermissionsMask.text) & accessLevel) > 0 )
				this.SetCommandVisibile(true, commandID);
			else
				this.SetCommandVisibile(!invisible, commandID);
	}
}
// Must be called after all HTML document downloaded if SetParent not called
// call this before calculating menu dimensions and showing menu
ContextMenu.prototype.Create = function(menuID, accessLevel)
{
	if(this.objParent == null)
		this.SetParent(document.body); // body may not exist when constructor is called
	this.rootMenuID = menuID;
	this.CreateSubMenu(menuID, accessLevel);
}
ContextMenu.prototype.CreateSubMenu = function(menuID, accessLevel)
{
	if(this.xmlDocMenu == null)
	{alert("Failed to load xml menu document"); return;}

	accessLevel = (accessLevel == null) ? -1 : parseInt(accessLevel.toString());
	
	var sheet = this.xslDocMenu.documentElement.selectSingleNode("/xsl:stylesheet");
	sheet.selectSingleNode("xsl:param[@name='access_level']").text = accessLevel;

	// fill all menu frames with html
	var nodeMenu = this.xmlDocMenu.selectSingleNode("//Menu[@ID='" + menuID + "' and Menu]");
	this.FillMenuFrame(nodeMenu.selectSingleNode("@ID").text);
	var nodesMenus = nodeMenu.selectNodes(".//Menu[Menu]");
	for(var i=0; i<nodesMenus.length; i++)
		this.FillMenuFrame(nodesMenus[i].selectSingleNode("@ID").text);
}
ContextMenu.prototype.FillMenuFrame = function(menuID)
{
	var frameID = this.thisObjID + "_" + menuID;

	var sheet = this.xslDocMenu.documentElement.selectSingleNode("/xsl:stylesheet");
	sheet.selectSingleNode("xsl:param[@name='menu_id']").text = menuID;

	var frame = document.all(frameID);
	frame.width = 300; // required to calculate internal html dimensions correctly
	frame.height = 300; // required to calculate internal html dimensions correctly

	var menuDocument = document.frames(frameID).document;
	menuDocument.write(this.xmlDocMenu.transformNode(this.xslDocMenu));
	menuDocument.close();
	var menuObj = menuDocument.all("menu");

////	frame.style.visibility = "hidden";	// required to calculate frame dimensions
////	frame.style.display = "";			// required to calculate frame dimensions
	frame.width = menuObj.offsetWidth;
	frame.height = menuObj.offsetHeight;
////	frame.style.display = "none";
////	frame.style.visibility = "";
}
ContextMenu.prototype.Popup = function(x, y)
{
	this.ShowMenu(this.rootMenuID, x, y);
}
ContextMenu.prototype.Hide = function()
{
	clearTimeout(this.hideTimerID);
	
	if(this.isMenuVisible!=true)
		return;
	this.isMenuVisible = false;

	var nodesMenuIDs = this.xmlDocMenu.selectNodes("//Menu[Menu]/@ID");
	for(var i=0; i<nodesMenuIDs.length; i++)
	{
		var frame = document.all(this.thisObjID + "_" + nodesMenuIDs[i].text);
		if(frame)
			frame.style.visibility = "hidden";
////			frame.style.display = "none";
	}
	
	if(top.document.activeMenu == this)
		top.document.activeMenu = null;
		
	for(var i=0; i!=this.aHideCallback.length; i++) 
	{
		if(this.aHideCallback[i]!=null)
		{
			this.aHideCallback[i]();
		}
		else
		{// remove callback
		}
	}
}
ContextMenu.prototype.onMouseOut = function(menuID)
{
	if(this.hideTimeout!=null)
	{
		top.menuHide = this;
		window.document.body.onmouseover = this.onParentWndMouseOver;
/*
		if(top.frames("other")!=null)
		{
			try
			{
				top.frames("other").document.body.onmouseover = this.onParentWndMouseOver; // for IE 5.0
			}
			catch(e){}
		}
*/		
	}
}
ContextMenu.prototype.onParentWndMouseOver = function()
{
	var menu = top.menuHide;
	if(menu!=null)
	{
		clearTimeout(menu.hideTimerID);
		menu.hideTimerID = setTimeout(menu.thisObjID + ".Hide()", menu.hideTimeout);
		top.menuHide = null;
	}

	window.document.body.onmouseover = null;
/*	
	var frames = window.document.frames;
	for(var i=0; i!=frames.length; i++)
		frames[i].document.body.onmouseover = null;
*/		
}
ContextMenu.prototype.onMouseOver = function(menuID)
{
	this.ShowMenu(menuID);
}
// Returns ContextMenu even from other frames or null if no active menu found. You can hide it for example in onscroll function
// In application only one context menu is active
ContextMenu.prototype.GetActiveMenuGlobal = function()
{
	return top.document.activeMenu;
}
ContextMenu.prototype.HideGlobal = function()
{
	if(top.document.activeMenu!=null)
	{
		try
		{
			top.document.activeMenu.Hide();
		}
		catch(e)
		{ // menu was deleted during frame reload
			top.document.activeMenu = null;
		}
	}
}
ContextMenu.prototype.ShowMenu = function(menuID, x, y, /*bool*/ useRestrictRctangle /*=true*/, minMenuWidth /*=0*/)
{
	this.isMenuVisible = true;
	
	clearTimeout(this.hideTimerID);

	// close active menu
	var saveObj = top.document;
	if(saveObj.activeMenu != this)
	{
		if ((saveObj.activeMenu!=null))
		{
			try
			{
				saveObj.activeMenu.Hide();
			}
			catch(e)
			{ // menu was deleted during frame reload
				top.document.activeMenu = null;
			}
		}
		saveObj.activeMenu = this;
	}
	
	var nodeMenu = this.xmlDocMenu.selectSingleNode("//Menu[@ID='" + menuID + "']");

	var nodesMenus = nodeMenu.selectNodes("..//Menu[Menu]");
	for(var i=0; i<nodesMenus.length; i++)
	{
		var curMenuID = nodesMenus[i].selectSingleNode("@ID").text;
		var curFrameID = this.thisObjID + "_" + curMenuID;
		var curFrame = document.all(curFrameID);
		curFrame.style.visibility = "hidden";
////		curFrame.style.display = "none";
	}

	// display new menu
	var frameID = this.thisObjID + "_" + menuID;
	var frame = document.all(frameID);
	if(frame != null)
	{
		var rcMenu = ( (x!=null) && (y!=null) ) ? new Rectangle(x, y, 0, 0) : this.GetMenuItemRectangle(menuID);

////		frame.style.visibility = "hidden";
////		frame.style.display = ""; //display first to calculate dimensions
		frame.style.posTop = rcMenu.top;
		frame.style.posLeft = rcMenu.left + rcMenu.width; // in IE 5.0 overlaping frames flipp
		
		//set min width
		if(minMenuWidth!=null && frame.offsetWidth<minMenuWidth)
		{
			var menuDocument = document.frames(frameID).document;
			var menuObj = menuDocument.all("menu");
			menuObj.style.posWidth = minMenuWidth;
			frame.style.posWidth = minMenuWidth;
		}

		// change z-order for correct shadow display
		var parentFrame = this.GetParentFrame(menuID);
		if(parentFrame!=null)
			frame.style.zIndex = parentFrame.style.zIndex + 1;
			
		if( (this.rcRestrict!=null) && (useRestrictRctangle!=false) )
		{
			// check if not too close to bottom
			var menuHeight = frame.offsetHeight;
			if(this.rcRestrict.top + this.rcRestrict.height < frame.offsetTop + menuHeight)
			{
				if((frame.style.posTop - menuHeight - rcMenu.height - this.shadowLength) > 0) // check if not to close to top
					frame.style.posTop -= menuHeight - rcMenu.height - this.shadowLength; //popup up
				else
					frame.style.posTop = this.rcRestrict.top + this.rcRestrict.height - menuHeight; // cannot fit
			}
				
			// check if not too close to right border
			var menuWidth = frame.offsetWidth;
			if(this.rcRestrict.left + this.rcRestrict.width < frame.offsetLeft + menuWidth)
			{
				if((rcMenu.left - menuWidth + this.shadowLength) > 0) // check if not to close to left
				{
					frame.style.posLeft = rcMenu.left - menuWidth + this.shadowLength; // popup left
					if(parentFrame!=null)
						frame.style.zIndex = parentFrame.style.zIndex - 1; // change z-order for correct shadow display
				}	
				else
				{
					frame.style.posLeft = this.rcRestrict.left; // cannot fit
					if(parentFrame!=null)
						frame.style.zIndex = parentFrame.style.zIndex + 1; // change z-order for correct shadow display
				}
			}
		}

		frame.style.visibility = "";
	}	
}
ContextMenu.prototype.GetParentFrame = function(menuID)
{
	var nodeMenu = this.xmlDocMenu.selectSingleNode("//Menu[@ID='" + menuID + "']");
	var nodeParentMenu = nodeMenu.selectSingleNode("../@ID");
	if(nodeParentMenu==null)
		return null;
	var parentMenuID = nodeParentMenu.text;
	var parentFrameID = this.thisObjID + "_" + parentMenuID;
	return document.all(parentFrameID);
}
ContextMenu.prototype.GetMenuItemRectangle = function(menuID)
{
	var nodeMenu = this.xmlDocMenu.selectSingleNode("//Menu[@ID='" + menuID + "']");
	var parentMenuID = nodeMenu.selectSingleNode("../@ID").text;
	var parentFrameID = this.thisObjID + "_" + parentMenuID;
	var parentFrame = document.all(parentFrameID);
	var parentDoc = document.frames(parentFrameID).document;
	var parentRow = parentDoc.all("row_" + menuID);
	return new Rectangle(
		parentFrame.offsetLeft,
		parentFrame.offsetTop + parentRow.offsetTop,
		parentFrame.offsetWidth - this.shadowLength,
		parentRow.offsetHeight);
}
ContextMenu.prototype.GetMenuFrameRectangle = function(menuID)
{
	var frameID = this.thisObjID + "_" + menuID;
	var frame = document.all(frameID);
	if(frame == null)
		return null;
////	frame.style.visibility = "hidden";
//	var displaySave = frame.style.display;
////	frame.style.display = ""; // required to calculate dimensions
	var rc = new Rectangle(frame.offsetLeft, frame.offsetTop, frame.offsetWidth, frame.offsetHeight);
//	frame.style.display = displaySave;
////	frame.style.display = "none";
////	frame.style.visibility = "";
	return rc; 
}
ContextMenu.prototype.SetCommandVisibile = function(/*bool*/ visible, commandID)
{
	var nodesMenu = this.xmlDocMenu.selectNodes("//Menu[@CommandID='" + commandID + "']");
	for(var i=0; i!=nodesMenu.length; i++)
	{
		var nodeVisible = nodesMenu[i].selectSingleNode("@Visible");
		if(nodeVisible == null)
		{// create attribute
			nodeVisible = this.xmlDocMenu.createAttribute("Visible");
			nodesMenu[i].attributes.setNamedItem(nodeVisible);
		}
		nodeVisible.text = visible ? "True" : "False"
	}
}
ContextMenu.prototype.SetRestrictRectangle = function(left, top, width, height)
{
	this.rcRestrict = new Rectangle(left, top, width, height);
}
ContextMenu.prototype.GetPreventCashNumber = function()
{
	return Date.parse(Date());
}
ContextMenu.prototype.onSelect = function(menuID)
{
	if (this.onSelectFunc != null)
		this.onSelectFunc(menuID);
}

ContextMenu.prototype.IsMSIE5 = function()
{
	if(this.isMSIE5 == null)
		if ( (window.clientInformation.userAgent.indexOf("MSIE 5")!=-1) &&
				(window.clientInformation.userAgent.indexOf("MSIE 5.5")==-1) )
			this.isMSIE5 = true;
		else
			this.isMSIE5 = false;
			
	return this.isMSIE5;
}

// Rectangle class
function Rectangle(left, top, width, height)
{
	if( (left==null) || (top==null) || (width==null) || (height==null) )
	{ alert("Failed to create rectangle"); return; }
	
	this.left = left;
	this.top = top;
	this.width = width;
	this.height = height;
}
ContextMenu.prototype.ExecCommand = function(commandID)
{
    eval(this.GetXmlDoc().selectSingleNode("//Command[@ID='" + commandID + "']").text);
}
