
function SF_Menu( m_oInitData )
{
	// constants
	
	// item states
	var c_nStateNone	= 0;
	var c_nStateHover	= 1;
	var c_nStateActive	= 2;
	var c_nStateExpanded= 3;		
	
	var c_nSlideNone	= 0;
	var c_nSlideConst	= 1;
	var c_nSlideAcc		= 2;
	var c_nSlideDec		= 3;
	
	// ContextMenu types
	var c_nContextMenuNone		= 0;
	var c_nContextMenuSimple	= 1;
	var c_nContextMenuControl	= 2;
	var c_nContextMenuCustom	= 3;
	
	var c_nSlideStep			= 1;
	var c_nSlideMinInt			= 40;
	var c_nSlideInstantMinInt	= 1;
	
	var c_nScrollingStep		= 4;
	var c_nScrollDelay			= 30;
	var c_nScrollStepDelay		= 20;
	
	var c_nTopPanelZIndex	= 500;
	var c_nPanelZIndex		= 499;

	var c_sAttrRootPanelID	= "RootPanID";
	var	c_sItemIdx			= "ItemIdx"
	var c_sAttrHostPanel	= "HostPanel";
	var c_sAttrParentItem	= "ParentItem";
	var c_sAttrSubMenu		= "SubMenu";
	var c_sAttrLayout		= "Layout";
	var c_sAttrIsItemCont	= "IsItemContainer";
	var c_sAttrOwnHeight	= "OwnHeight";
	var c_sAttrItemClass	= "ItemClass";
	var c_sAttrAccessKey	= "accessKey";

	var c_sAttrClntID			= "ClntID";
	var c_sAttrClntText			= "ClntText";
	var c_sAttrClntTooltip		= "ClntTooltip";
	var c_sAttrIsDisabled		= "ClntIsDisabled";
	var c_sAttrIsChecked		= "ClntIsChecked";
	var c_sAttrNaviURL			= "ClntNaviURL";	
	var c_sAttrTarget			= "ClntTarget";
	var c_sAttrIsScrollUpNotDown= "UpNotDown";
		
	var c_sAttrExpandFilter		= "ExpandFilter";
	var c_sAttrCollapseFilter	= "CollapseFilter";
	var c_sAttrSubPanOffsetX	= "SubPanOffsetX";
	var c_sAttrSubPanOffsetY	= "SubPanOffsetY";
	
	var c_sOnItemSelect		= "ClientOnItemSelect";
	var c_sOnItemMouseOver	= "ClientOnItemMouseOver";
	var c_sOnItemMouseOut	= "ClientOnItemMouseOut";
	
	var c_sAttrValLayHorz	= "Horizontal";
	var c_sAttrValLayVert	= "Vertical";
	var c_sAttrValClassSep	= "Separator";	
	
	var c_sFloatPanelsContainerIDPart	= "_FloatPanelsContainer";
	var c_sTerminatorIDPart				= "_Terminator";

    var c_nMaxTimeToLoad = 1000;
    var c_nRepeatLoadInterval = 10;

	// internals
	var self = this;
	var UTIL = new SF_Util();
	var DOM = new SF_DOM( { UTIL: UTIL } );
	var CSS = new SF_CSS( { DOM: DOM } );
	
	// fields
	var m_nContextMenuType	= 0;
	var m_sContextControlID	= "";
	
	var m_nExpandDelay		= 100;
	var m_nExpandDuration	= 500;
	
	var m_nCollapseDelay	= 200;
	var m_nCollapseDuration	= 500;

	var m_nExpandType		= c_nSlideNone;
	var m_nCollapseType		= c_nSlideNone;

	var m_nExpandTrans		= CSS.TransitionNone;
	var m_nCollapseTrans	= CSS.TransitionNone;

	var m_bUseFrames		= false;
	var m_bExpandOnClick	= false;
	var m_bCollapseCascaded = true;
	
	var m_bScrollingEnabled	= false;
	
	var m_oRootEl = null;
	var m_oFloaterEl = null;
	var m_oRootPanEl = null;
	var m_oTerm = null;

	var m_aElCache = [];
	var m_aPanelCache = [];

	var m_oCurExpandingParams = null;
	var m_oPinnedPanels = {};
	
	var m_aShortcuts = {};
	var m_aMnemonics = {};
	var m_oPanelMnemonics = {};
	var m_oStaticPanelMnemonics = {};
	var m_oItemMnemonics = {};
	var m_arrPanelIDs = [];
	
	var m_sOnClientItemSelect = null;
	var m_sOnClientMouseOver = null;
	var m_sOnClientMouseOut = null;
	
	var m_oPreviousExpandedPanel = null;
	var m_oPreviousHoverItem	 = null;
	var m_oPreviousHoverPanel	 = null; 
	var m_oMnemonicHoverItem	 = null; 
	var m_oHoverPanel			 = null; 
	var m_oHoverItem			 = null; 
	
	var m_bNoClickExpand = false;
	
	var m_nExpandTimer = null;
	
	var m_oScrollingEl = null;
	
	var m_bIsInited = false;
	var m_bIsErrorInited = false;
		
	/////////////////////////////////////////////////////////////////////////
	// public
		
	this.TransitionNone		= CSS.TransitionNone;
	this.TransitionFade		= CSS.TransitionFade;
	this.TransitionDissolve	= CSS.TransitionDissolve;
	this.TransitionPixelate	= CSS.TransitionPixelate;
	this.TransitionWipeDown	= CSS.TransitionWipeDown;
	this.TransitionWipeLeft	= CSS.TransitionWipeLeft;
	this.TransitionWipeRight= CSS.TransitionWipeRight;
	this.TransitionWipeUp	= CSS.TransitionWipeUp;
	
	this.SetContextMenu = function( nVal )
	{
		m_nContextMenuType = nVal;
	}
	
	this.GetContextMenu = function( )
	{
		return m_nContextMenuType;
	}
	
	this.SetContextControlID = function( sVal )
	{
		m_sContextControlID	= sVal;
	}
	
	this.GetContextControlID = function()
	{
		return m_sContextControlID;
	}
	
	this.SetExpandDelay = function( nVal )
	{
		m_nExpandDelay = nVal;
	}

	this.GetExpandDelay = function()
	{
		return m_nExpandDelay;
	}

	this.SetExpandDuration = function( nVal )
	{
		m_nExpandDuration = nVal;
	}

	this.GetExpandDuration = function()
	{
		return m_nExpandDuration;
	}

	this.SetCollapseDelay = function( nVal )
	{
		m_nCollapseDelay = nVal;
	}

	this.GetCollapseDelay = function()
	{
		return m_nCollapseDelay;
	}

	this.SetCollapseDuration = function( nVal )
	{
		m_nCollapseDuration = nVal;
	}

	this.GetCollapseDuration = function()
	{
		return m_nCollapseDuration;
	}

	this.SetExpandType = function( nType )
	{
		m_nExpandType = nType;
	}

	this.GetExpandType = function()
	{
		return m_nExpandType;
	}

	this.SetCollapseType = function( nType )
	{
		m_nCollapseType = nType;
	}

	this.GetCollapseType = function()
	{
		return m_nCollapseType;
	}

	this.SetExpandTransition = function( nVal )
	{
		m_nExpandTrans	= nVal;
	}

	this.GetExpandTransition = function()
	{
		return m_nExpandTrans;
	}

	this.SetCollapseTransition = function( nVal )
	{
		m_nCollapseTrans = nVal;
	}

	this.GetCollapseTransition = function()
	{
		return m_nCollapseTrans;
	}

	this.SetUseFrames = function( bVal )
	{
		m_bUseFrames = bVal;
	}

	this.GetUseFrames = function()
	{
		return m_bUseFrames;
	}

	this.SetExpandOnClick = function( bVal )
	{
		m_bExpandOnClick = bVal;
	}

	this.GetExpandOnClick = function()
	{
		return m_bExpandOnClick;
	}
	
	this.SetCollapseCascaded = function( bVal )
	{
		m_bCollapseCascaded = bVal;
	}

	this.GetCollapseCascaded = function()
	{
		return m_bCollapseCascaded;
	}
	
	this.SetScrollingEnabled = function( bVal )
	{
		m_bScrollingEnabled  = bVal;
	}

	this.GetScrollingEnabled  = function()
	{
		return m_bScrollingEnabled ;
	}
	
	this.RegisterShortcut = function ( sShortcut, sID )
	{
		m_aShortcuts[ sShortcut ] = sID;
	}
	
	this.RegisterMnemonics = function ( sMnemonics, sPanelID )
	{
		m_aMnemonics[ sPanelID ] = sMnemonics;
		m_arrPanelIDs[ m_arrPanelIDs.length ] = sPanelID;
	}

	this.OnMouseOver = function( oEl, oEv )
	{		
//		DBG( "OnMouseOver:\t" + oEl.id );
		if (IsInited() && !oEl.IsMouseOn)
			DoOnMouseOver( oEl, oEv, true, true );
	}

	this.OnMouseMove = function( oEl, oEv )
	{
//		DBG( "OnMouseMove:\t" + oEl.id );
		if (IsInited())			
			DoOnMouseMove( oEl, oEv );
	}
	
	this.OnMouseOut = function( oEl, oEv )
	{		
//			DBG( "OnMouseOut:\t" + oEl.id );
			if (IsInited() && DOM.IsCompleteMouseOut( oEl, oEv ))
				DoOnMouseOut( oEl, oEv, true, true );
	}

	this.OnMouseDown = function( oEl, oEv )
	{
		if (IsInited())
			DoOnMouseDown( oEl, oEv );
	}

	this.OnMouseUp = function( oEl, oEv )
	{
		if (IsInited())
			DoOnMouseUp( oEl, oEv );
	}

	this.OnClick = function( oEl, oEv )
	{
		if (IsInited())
			DoOnClick( oEl, oEv );
	}
	
	this.OnFocus = function( oEl, oEv )
	{
		if (IsInited())
		{
			var sTargID = GetStrAttribute( oEl, c_sAttrClntID );
			if (sTargID)
			{
				var oItem = GetOwnEl( sTargID );
				if (oItem)
				{
					var cKey = DOM.GetAttribute( oEl, c_sAttrAccessKey );
					if( cKey )
					{
						CallMnemonic( cKey, oEv, true );
					}
					oItem.m_oAccessKeyEl = oEl;
				}
			}
		}		
	}
	
	this.OnMouseOutScrollEl = function( oEl, oEv )
	{
		if (IsInited() && self.GetScrollingEnabled() )
		{
			StopScroll( oEl, oEv );			
		}
	}
	
	this.OnMouseOverScrollEl = function( oEl, oEv )
	{
		if (IsInited() && self.GetScrollingEnabled() )
		{
			DoScroll( oEl );
		}
	}
	
	this.ShowContextMenu = function( x, y, oEv, oContextData )
	{
		var bRes = false;
		if( c_nContextMenuCustom == this.GetContextMenu() )
		{
			bRes = DoShowContextMenu( x, y, oEv );
			self.ContextData = oContextData;
		}
		return bRes;
	}
	
	this.Create = function()
	{
	    ctor();
	}
	
	this.Refresh = function( sArg )
	{
	    DOM.ControlRefresh( self, sArg );
	}

	/////////////////////////////////////////////////////////////////////////
	// private
	function ctor()
	{
	    self.id = m_oInitData.ID; // for callback
		DOM.RegisterOnCreate( Create, PreCreatePred );
	}

	function PreCreatePred()
	{
		return (
			(m_oRootEl = DOM.GetElById( m_oInitData.ID )) &&
			(m_oTerm = DOM.GetElById( m_oInitData.ID + c_sTerminatorIDPart ))
			);
	}
	
	function Create()
	{
	    setTimeout( OnTimeOutCreate, c_nMaxTimeToLoad );
		InitPanelsStorage();
		InitImagesStorage();
		
		DOM.AttachEvent( DOM.EEventNames.KeyDown, DoOnKeyDown, null );
		
		var oParentEl = null;
		
		if( self.GetContextMenu() == c_nContextMenuSimple )
		{
			oParentEl = DOM.GetTopmostLayoutEl();
		}
		else if( self.GetContextMenu() == c_nContextMenuControl )
		{
			var sContextControlId = self.GetContextControlID();
			if( sContextControlId )
			{
				var oContextControl = DOM.GetElById( sContextControlId );
				if( oContextControl )
				{
					oParentEl = oContextControl;
				}
			}			
		}
		
		if( null != oParentEl )
		{
		    DOM.AttachEvent( DOM.EEventNames.ContextMenu, OnContextMenu, oParentEl );
		    DOM.AttachEvent( DOM.EEventNames.ContextMenu, DOM.EventCancel, m_oFloaterEl );
		}
		
		if( IsContextMenu() )
		{
			DOM.AttachEvent( DOM.EEventNames.MouseDown, DoCollapseRootPanel, null );
			
		}
		else
		{
			DOM.AttachEvent( DOM.EEventNames.MouseDown, DoCollapse, null );
		}
		
		DOM.AttachEvent( DOM.EEventNames.MouseDown, DOM.EventCancel, m_oFloaterEl );
		
		DOM.AddAtlasFeatures( m_oRootEl, Dispose );
	}
	
	function Dispose()
	{
	    DOM.DestroyTree( m_oFloaterEl );
	    
	    DOM.DetachEvent( DOM.EEventNames.KeyDown, DoOnKeyDown, null );
	    
	    var oParentEl = null;		
		if( self.GetContextMenu() == c_nContextMenuSimple )
		{
			oParentEl = DOM.GetTopmostLayoutEl();
		}
		else if( self.GetContextMenu() == c_nContextMenuControl )
		{
			var sContextControlId = self.GetContextControlID();
			if( sContextControlId )
			{
				var oContextControl = DOM.GetElById( sContextControlId );
				if( oContextControl )
				{
					oParentEl = oContextControl;
				}
			}			
		}
		
		if( null != oParentEl )
		{
		    DOM.DetachEvent( DOM.EEventNames.ContextMenu, OnContextMenu, oParentEl );
		    DOM.DetachEvent( DOM.EEventNames.ContextMenu, DOM.EventCancel, m_oFloaterEl );
		}
		
		if( IsContextMenu() )
		{
			DOM.DetachEvent( DOM.EEventNames.MouseDown, DoCollapseRootPanel, null );
		
		}
		else
		{
			DOM.DetachEvent( DOM.EEventNames.MouseDown, DoCollapse, null );
		}
		
		DOM.DetachEvent( DOM.EEventNames.MouseDown, DOM.EventCancel, m_oFloaterEl );
	    
	}
		
	/////////////////////////////////////////////////////////////////////////
	// message handling
	function DoOnKeyDown( oEv )
	{
		var sShortcut = DetectShortcut( oEv );
		if ( sShortcut )
		{			
			var sID = m_aShortcuts[ sShortcut ];
			if ( sID )
			{
				var oItem = GetItemEl( sID );
				if ( oItem )
				{
					ProcessItemSelection( oItem, oEv );
					DOM.EventCancel( oEv, true );
				}
			}
		}
	
		var nKeyCode = oEv.keyCode;
		
		if( UTIL.IsNavigationKey( nKeyCode ) )
		{
			if( ( null != m_oHoverItem )&&( null == DOM.GetAttribute( m_oHoverItem,c_sAttrIsScrollUpNotDown ) ) )
			{
				var oSubEl = GetSubMenuEl( m_oHoverItem );
				
				var bExpandSubMenu = ( null != oSubEl ) && ( oSubEl.IsExpanded || oSubEl.IsCollapsing || oSubEl.IsExpanding ) && !GetIsStaticPanel( oSubEl );
				
				DoNavigation( m_oHoverItem, oEv, bExpandSubMenu );
				DOM.EventCancel( oEv, true );
			}
		}
		else if( UTIL.IsEnterKey( nKeyCode ) )
		{
			if( m_oHoverItem )
			{
				DoExpandSubEl( m_oHoverItem, oEv, true );
				DOM.EventCancel( oEv, true );				
			}
		}
		else if( UTIL.IsEscKey( nKeyCode ) )
		{			
			DoCollapseSubPanel( oEv );
		}
		else if( UTIL.IsDigitOrLetterKey( nKeyCode ) )
		{
			DetectMnemonic( oEv );
		}	
	}	

	function DoOnMouseOver( oEl, oEv, bReallyMouseOver, bExpandSubPanel )
	{
		m_oRootPanEl.CanCollapse = false;
		if( !IsItemContainer( oEl ) )
		{				
			ProcessOnClientMouseOver( oEl, oEv );

			var oPanelEl = GetHostPanelEl( oEl );
			ASSERT( null != m_oItemMnemonics[ oEl.id ] );
			var cMnem = m_oItemMnemonics[ oEl.id ].Mnemonic;//oEl.Mnemonic;
			var nIndex = m_oItemMnemonics[ oEl.id ].nMnemonicIndex;//oEl.nMnemonicIndex;
				
			
			var oPanelMnemonics = GetPanelMnemonicsStorage( oPanelEl );
			oPanelMnemonics[ cMnem ].HoverItemIndex = nIndex;
				
			if( bReallyMouseOver && m_oMnemonicHoverItem &&( m_oMnemonicHoverItem != oEl ) )
			{
				DoOnMouseOut( m_oMnemonicHoverItem, oEv, false, true );
				
				if( ( oPanelEl != GetHostPanelEl( m_oMnemonicHoverItem ) ) )
				{
					var oSubEl = GetSubMenuEl( oEl );
					var oMnemonicHoverPanel = GetHostPanelEl( m_oMnemonicHoverItem );
					if( oSubEl && oSubEl == oMnemonicHoverPanel )
					{
						DoOnMouseOut( oMnemonicHoverPanel, oEv, true, true );
					}
					else
					{
						DoOnMouseOut( oMnemonicHoverPanel, oEv, false, true );
					}
					DoOnMouseOver( oPanelEl, oEv, true, false );
				}
			}
		
			m_oMnemonicHoverItem = bReallyMouseOver ? null : oEl;
				
			HiliteHover( oEl );
			var oSubEl = GetSubMenuEl( oEl );
			
			if ( self.GetExpandOnClick() && bReallyMouseOver )
			{
				if( m_oPreviousHoverItem && m_oPreviousHoverItem != oEl )
				{
					var oSubMenuEl = GetSubMenuEl( m_oPreviousHoverItem );
					if( oSubMenuEl ) 
					{
						CancelCollapseStarter( oSubMenuEl );
						if( oSubMenuEl.IsExpanding && oSubMenuEl != oPanelEl )
						{
							ExecCollapsing( m_oPreviousHoverItem, 0, true );
						}
						else
						{
							ExecCollapsing( m_oPreviousHoverItem, m_nCollapseDelay, true );
						}
					}
					else
					{
						if( m_oPreviousHoverPanel && ( m_oPreviousHoverPanel != oPanelEl ) && ( !oSubEl ||( oSubEl && oSubEl != m_oPreviousHoverPanel ) ) )
						{
							CancelCollapseStarter( m_oPreviousHoverPanel );
							MarkPanelHover( m_oPreviousHoverPanel, false );	
							
							ExecCollapsing( m_oPreviousHoverPanel, m_nCollapseDelay, true );
						}														
					}
				}				
			}				
			
			if( bExpandSubPanel &&( !self.GetExpandOnClick() || null != m_oPreviousExpandedPanel || m_bNoClickExpand ))
			{
				CancelCollapseStarter( oSubEl );
				ExecExpanding( oEl, oSubEl, ( bReallyMouseOver ? m_nExpandDelay : 0 ), !bReallyMouseOver );
			}
			
		}
		else
		{			
			CancelCollapseStarter( oEl );
			
			if( self.GetExpandOnClick() )
			{
				if( m_oPreviousHoverPanel )
				{
					MarkPanelHover( m_oPreviousHoverPanel, false );
				}
			}
			MarkPanelHover( oEl, true );
			if( !IsRootContainer( oEl ) && 
				( oEl.IsExpanded || oEl.IsExpanding ))
			{
				var oPar = GetParentItemEl( oEl );
				HiliteExpanded( oPar );
			}				
		}
		oEl.IsMouseOn = true;	
	}

	function DoOnMouseOut( oEl, oEv, bReallyMouseOut, bCollapseParentPanel )
	{
		oEl.IsMouseOn = false;		
		if( IsItemContainer( oEl ) )
		{
			if( !self.GetExpandOnClick() || !bReallyMouseOut )
			{			
				MarkPanelHover( oEl, false );	
				ExecCollapsing( oEl, bReallyMouseOut ? m_nCollapseDelay : 10, bCollapseParentPanel );
			}		
			m_oPreviousHoverPanel  = oEl;	
		}	
		else
		{			
			ProcessOnClientMouseOut( oEl, oEv );

			var oHostEl = GetHostPanelEl( oEl );
			if( oHostEl )
			{
				oHostEl.ItemHover = null;
			}	
			UnHiliteHover( oEl );
			
			if( bReallyMouseOut )
			{
				PrepareExecCollapsing( oEl );
				if( !self.GetExpandOnClick() )
				{									
					ExecCollapsing( oEl, bReallyMouseOut ? m_nCollapseDelay : 0, bCollapseParentPanel );					
				}
				m_oPreviousHoverItem  = oEl;				
			}
			
			if( oEl.m_oAccessKeyEl && oEl.m_oAccessKeyEl.blur )
			{
				oEl.m_oAccessKeyEl.blur();
			}
		}
	}
	
	function DoOnMouseMove( oEl, oEv )
	{
	
	}
	
	function DoOnMouseDown( oEl, oEv )
	{
	
	}

	function DoOnMouseUp( oEl, oEv )
	{

	}

	function DoOnClick( oEl, oEv )
	{
		var oSubMenu = GetSubMenuEl( oEl );
		if( oSubMenu && !GetIsStaticPanel( oSubMenu ) )
		{
			if( !self.GetExpandOnClick() )
			{
				ProcessItemSelection( oEl, oEv );
			}
			else
			{		
				var oSubEl = GetSubMenuEl( oEl );
				if( !( oSubEl.IsExpanded || oSubEl.IsExpanding ) )
				{
					m_bNoClickExpand = true;
					ExecExpanding( oEl, oSubEl, 0, false );
				}
			}
		}
		else
		{
			ProcessItemSelection( oEl, oEv );
		}
	}
	
	function DoShowContextMenu( x, y, oEv )
	{
		var bRes = false;
		
		RestartMenuState();		
		
		var oSl = GetSlideEls( m_oRootPanEl );
		var oHostEl = oSl.oHostEl;		
		
		var oPosition = SetContextMenuPosition( oEv, oHostEl, x, y );
		bRes = oPosition.Result;
		
		if( bRes )
		{
			m_oRootPanEl.IsExpanding = true;

			InvokeExpanding( m_oRootPanEl, null, false, !oPosition.IsLeft, 0, true, false  );
		}		
		return bRes;
	}
	
	function DoScroll( oEl )
	{
		if( oEl && !oEl.IsMouseOn )
		{		
			oEl.IsMouseOn = true;
			HiliteHover( oEl, true );
			m_oScrollingEl = oEl;
			oEl.IsScrolling = true;
			var oPanEl = DOM.GetParentEl( oEl );
			
			var bScrollUp = UTIL.IsTrue( DOM.GetAttribute( oEl, c_sAttrIsScrollUpNotDown ) );
			var nScrollStep = DOM.IsClipSlow() ? ( 2*c_nScrollingStep ) : c_nScrollingStep;
			
			var oParams = 
			{
				bScrollUp		: bScrollUp,
				nScrollStep		: nScrollStep,
				bScrollNext		: true,
				oScrollingEl	: oEl
			};

			function FnProxy()
			{	
				ExecScrollStep( oParams );
			}
			oPanEl.ScrollTimer = setTimeout( FnProxy, c_nScrollDelay );			
		}
	}
	
	function StopScroll( oEl, oEv )
	{
		if( oEl && DOM.IsCompleteMouseOut( oEl, oEv ) )
		{
			oEl.IsMouseOn = false;
			UnHiliteHover( oEl, true );
					
			oEl.IsScrolling = false;
			m_oScrollingEl = null;
			var oPanEl = DOM.GetParentEl( oEl );
			if( null != oPanEl.ScrollTimer )
			{
				clearTimeout( oPanEl.ScrollTimer );
			}			
		}
	}
	
	/////////////////////////////////////////////////////////////////////////
	// Navigation
	
	function DoExpandSubEl( oParItemEl, oEv, bNoExpandSelect )
	{
		var oSubMenu = GetSubMenuEl( oParItemEl ); 
		if( oSubMenu && !GetIsStaticPanel( oSubMenu ) )
		{
			var oSubEl = GetSubMenuEl( oParItemEl );
			if( !( oSubEl.IsExpanded || oSubEl.IsExpanding ) )
			{
				ExecExpanding( oParItemEl, oSubEl, 0, true );
			}
		}
		else if( bNoExpandSelect )
		{
			ProcessItemSelection( oParItemEl, oEv );
		}
		DOM.EventCancel( oEv, true );
	}
	
	function DoCollapseSubPanel( oEv )
	{
		var oRootEl = GetRootPanelEl();
		if( IsContextMenu() && m_oPreviousExpandedPanel && GetIsStaticPanel( m_oPreviousExpandedPanel ) )
		{
			oRootEl.CanCollapse = true;
		}
			
		if( m_oHoverItem )
		{
			var oSubMenu = m_oHoverItem ? GetSubMenuEl(m_oHoverItem) : null;
			if( oSubMenu && oSubMenu.IsExpanding )
			{
				InvokeCollapsing( oSubMenu, GetHostPanelEl( m_oHoverItem ), 0, false );
				if( m_oHoverItem )
				{
					HiliteExpanded( m_oHoverItem );
				}
			}
			else
			{
				DoOnMouseOut( m_oHoverItem, oEv, false, false );
				if( m_oPreviousExpandedPanel )
				{
					DoOnMouseOut( m_oPreviousExpandedPanel, oEv, false, false );
					if( GetIsStaticPanel( m_oPreviousExpandedPanel ) && !IsRootContainer( m_oPreviousExpandedPanel ) )
					{
						DoOnMouseOut( m_oRootPanEl , oEv, false, false);	
					}					
				}
				else
				{
					m_bNoClickExpand = false;
				}
			}
			DOM.EventCancel( oEv, true );
		}
		else //if( self.GetExpandOnClick() )
		{			
			if( m_oPreviousExpandedPanel )
			{
				DoOnMouseOut( m_oPreviousExpandedPanel, oEv, false, false);	
				if( m_oPreviousExpandedPanel == GetRootPanelEl() )
				{
					m_bNoClickExpand = false;
				}
				DOM.EventCancel( oEv, true );
			}
		}
	}
	
	function DetectMnemonic( oEv )
	{
		var nKeyCode = oEv.keyCode;		
		var oSubEl = ( null != m_oHoverItem ) ? GetSubMenuEl( m_oHoverItem ) : null;
		var bMouseOnParentItem =( (null != oSubEl) && oSubEl.IsExpanded );		
		if( UTIL.IsDigitOrLetterKey( nKeyCode ) )
		{			
			if( ( IsContextMenu() && GetRootPanelEl().IsExpanded )||
				( !IsContextMenu() &&( ( m_oHoverPanel && m_oHoverPanel.IsExpanded )|| bMouseOnParentItem )))
			{
				var cKey = String.fromCharCode( nKeyCode );
				CallMnemonic( cKey, oEv, false );
			}
		}
	}
	
	function CallMnemonic( cKey, oEv, bFromAccessKey )
	{
		var oSubEl = ( null != m_oHoverItem ) ? GetSubMenuEl( m_oHoverItem ) : null;
		var bMouseOnParentItem =( (null != oSubEl) && oSubEl.IsExpanded );
		
		var oMnemonicPanel = null;
		if( oEv.altKey && !bFromAccessKey )
		{
			return;		
		}
		else if( bFromAccessKey )
		{
			oMnemonicPanel = GetRootPanelEl();
		}
		else if( bMouseOnParentItem )
		{
			oMnemonicPanel = oSubEl;			
		}
		else
		{
			oMnemonicPanel = ( m_oHoverPanel && m_oHoverPanel.IsExpanded )? m_oHoverPanel : GetRootPanelEl();
		}			
		
		var oPanelMnemonic = GetPanelMnemonicsStorage( oMnemonicPanel )[cKey];
		if( oPanelMnemonic )
		{
			var oItems = oPanelMnemonic.m_nItemsNoSep;				
			var nIdx = oPanelMnemonic.HoverItemIndex;
			if( m_oHoverItem )
			{
				DoOnMouseOut( m_oHoverItem, oEv, false, true );
			}
			if( oMnemonicPanel != m_oHoverPanel )
			{
				if( null != m_oHoverPanel )
				{
					DoOnMouseOut( m_oHoverPanel, oEv, false, true );
				}
				DoOnMouseOver( oMnemonicPanel, oEv, false, false );				
			}
			
			var oHoverItem = null;
			
			if( 1 == oItems.length )
			{
				oHoverItem = oItems[0];
				
				var oSubMenu = GetSubMenuEl( oHoverItem );
				if( oSubMenu && !GetIsStaticPanel( oSubMenu ) )
				{
					m_bNoClickExpand = true;
					DoOnMouseOver( oHoverItem, oEv, false, true );
				}
				else
				{
					DoOnMouseOver( oHoverItem, oEv, false, true );
					ProcessItemSelection( oHoverItem, oEv );
				}						
			}
			else
			{
				var nNewIndex = ( (-1 == nIdx)||( nIdx == oItems.length - 1 ) )? 0: ( nIdx +1);
				oHoverItem = oItems[nNewIndex];
				DoOnMouseOver( oHoverItem, oEv, false, false );
				oPanelMnemonic.HoverItemIndex = nNewIndex;
			}
			
			if( null != oHoverItem )
			{
				var oHostPanel = GetHostPanelEl( oHoverItem );
				if( !GetIsStaticPanel( oHostPanel ) && self.GetScrollingEnabled() &&( oHostPanel.IsExpanding || oHostPanel.IsCollapsing || oHostPanel.IsExpanded ) )
				{
					DoScrollIntoView( oHoverItem );
				}
			}
			
			DOM.EventCancel( oEv, true );
		}
	}
	
	function DoNavigation( oHoverItem, oEv, bSubExpand )
	{
		var nKeyCode = oEv.keyCode;
		var bUp			= UTIL.IsUpArrowKey( nKeyCode );
		var bDown		= UTIL.IsDownArrowKey( nKeyCode );
		var bLeft		= UTIL.IsLeftArrowKey( nKeyCode );
		var bRight		= UTIL.IsRightArrowKey( nKeyCode );
		var bHome		= UTIL.IsHomeKey( nKeyCode );
		var bEnd		= UTIL.IsEndKey( nKeyCode );
		var bPageUp		= UTIL.IsPageUpKey( nKeyCode );
		var bPageDown	= UTIL.IsPageDownKey( nKeyCode );
		
		if( null != oHoverItem )
		{
			var nIndex = m_oItemMnemonics[ oHoverItem.id ].nIndex;
			var oSubEl = GetSubMenuEl( oHoverItem );
			var oHoverPanel = GetHostPanelEl( oHoverItem );
							
			var bRTL = IsMenuRightToLeft();
			
			//if rtl change Left and Right
			if( bRTL )
			{
				var b = bLeft;
				bLeft = bRight;
				bRight = b;
			}
			
			// next/ previous menu item
			if( bPageUp || bPageDown || bHome || bEnd ||( IsPanelLayoutVert( oHoverPanel )&&( bUp || bDown ) )||( !IsPanelLayoutVert( oHoverPanel )&&( bLeft || bRight ) ) )
			{
				var nItemCount = GetMnemonicsCount( oHoverPanel );
				var oNextHoverItem = oHoverItem;
				var nNextIndex = -1;
				if( bPageUp || bPageDown )
				{
					if( self.GetScrollingEnabled() && !GetIsStaticPanel( oHoverPanel ) )
					{
						var oScrollEls = GetScrollEls( oHoverPanel );
						var oScrollPanEl = oScrollEls.oScrollPanelEl;
						var	oScrollDownEl = oScrollEls.oScrollDownEl; 
						
						var nItemHeight = oHoverItem.offsetHeight;
						var nScrollPanHeight = oScrollPanEl.offsetHeight;
						var nScrollerHeight = oScrollDownEl.offsetHeight;
						var nPanelHeight = oHoverPanel.offsetHeight - DOM.GetElementExtHeight( oHoverPanel, true) - DOM.GetElementExtHeight( oHoverPanel, false ) - 2*nScrollerHeight;
						var nCurrentIndex = m_oItemMnemonics[ oHoverItem.id ].nIndex;
						
						var nScrollStepItems = Math.max( parseInt( nPanelHeight / nItemHeight ), 1);
						if( bPageUp )
						{
							nNextIndex = ( nCurrentIndex - nScrollStepItems < 0 ) ? 0 : ( nCurrentIndex - nScrollStepItems );
						}
						else
						{
							nNextIndex = ( nCurrentIndex + nScrollStepItems > ( nItemCount -1 ) ) ? ( nItemCount -1 ) : ( nCurrentIndex + nScrollStepItems);
						} 
					}
					else
					{
						if( GetIsStaticPanel( oHoverPanel ) )
						{
							oNextHoverItem = bPageUp ? GetItem( m_oRootPanEl, 0 ) : GetLastItem();
						}
						else
						{
							nNextIndex = bPageUp ? 0 : ( nItemCount -1 );
						}
					}
				}
				else if( bHome || bEnd )
				{
					if( GetIsStaticPanel( oHoverPanel ) )
					{
						oNextHoverItem = bHome ? GetItem( m_oRootPanEl, 0 ) : GetLastItem();
					}
					else
					{
						nNextIndex = bHome ? 0 : ( nItemCount -1 );
					}
				}
				else if( bUp || bLeft )
				{
					if( GetIsStaticPanel( oHoverPanel ) )
					{
						if( nIndex > 0 )
						{
							oNextHoverItem = GetPreviousChildItem( oHoverItem );
						}
						else
						{
							oNextHoverItem = IsRootContainer( oHoverPanel ) ? GetLastItem() : GetParentItemEl( oHoverPanel );
						}
					}
					else
					{
						nNextIndex = ( nIndex > 0 ) ? (nIndex - 1) : nItemCount - 1;
					}
				}
				else
				{
					if( GetIsStaticPanel( oHoverPanel ) )
					{
						oNextHoverItem = GetNextItem( oHoverItem, true ); 
					}
					else
					{
						nNextIndex = ( nIndex + 1 < nItemCount ) ? (nIndex + 1) : 0; 
					}
				}				
				if( -1 != nNextIndex )
				{
					oNextHoverItem = GetItem( oHoverPanel, nNextIndex );
				}
				var oNextHoverPanel = GetHostPanelEl( oNextHoverItem );
				if( !GetIsStaticPanel( oNextHoverPanel ) && self.GetScrollingEnabled() && IsPanelLayoutVert( oNextHoverPanel ) )
				{
					DoScrollIntoView( oNextHoverItem );
				}
				
				if( oHoverItem != oNextHoverItem )
				{
					DoOnMouseOut( oHoverItem, oEv, false, bSubExpand );
					if( bSubExpand )
					{
						DoOnMouseOut( oSubEl, oEv, false, false );
					}
					if( oHoverPanel != oNextHoverPanel )
					{
						DoOnMouseOut( oHoverPanel, oEv, false, false );
						DoOnMouseOver( oNextHoverPanel, oEv, false, false );
					}
					DoOnMouseOver( oNextHoverItem, oEv, false, bSubExpand );
				}
			}
			else
			{
				// expand subpanel and navigate to subpanel items
				if( ( IsPanelLayoutVert( oHoverPanel )&& bRight )|| ( !IsPanelLayoutVert( oHoverPanel )&& bDown ) )
				{
					if( oSubEl && ( oSubEl.IsExpanded || GetIsStaticPanel( oSubEl ) ) &&( GetMnemonicsCount( oSubEl ) > 0 ) )
					{
						var oNextHoverItem = GetItem( oSubEl, 0 );
						
						DoOnMouseOut( oHoverItem, oEv, false, false );
						if( bSubExpand )
						{
							DoOnMouseOut( oHoverPanel, oEv, false, false );
							DoOnMouseOver( oSubEl, oEv, false, false );
						}
						DoOnMouseOver( oNextHoverItem, oEv, false, false );
						
					}
					else
					{
						//collapse subpanel and navigate to next foreparent item 
						if( HasSubMenu( oHoverItem ) )
						{					
							DoExpandSubEl( oHoverItem, oEv, false);
						}
						else if( !GetIsStaticPanel( oHoverPanel ) )
						{
							var oNextItem = GetNextForeparentItem( oHoverItem, true, !IsPanelLayoutVert( oHoverPanel ) );
							if( oNextItem && ( oNextItem != oHoverItem ))
							{
								var oNextHoverPanel = GetHostPanelEl( oNextItem );
								DoOnMouseOut( oHoverItem, oEv, false, true);
								if( oNextHoverPanel != oHoverPanel )
								{
									DoOnMouseOut( oHoverPanel, oEv, false, true);
									DoOnMouseOver( oNextHoverPanel, oEv, false, true);
								}
								DoOnMouseOver( oNextItem, oEv, false, true);
							}
						}
					}
				}
				//collapse subpanel and navigate to parent item
				else if( !GetIsStaticPanel( oHoverPanel ))
				{
					var oParentItem = GetParentItemEl( oHoverPanel );
					var oParentPanelEl = GetHostPanelEl( oParentItem );
					if( IsPanelLayoutVert( oParentPanelEl ) == IsPanelLayoutVert( oHoverPanel ) )
					{
						DoCollapseSubPanel( oEv );
					}
					else
					{
						//collapse subpanel and navigate to previous foreparent item 
						var oNextItem = GetNextForeparentItem( oHoverItem, false, !IsPanelLayoutVert( oHoverPanel ) );
						
						if( oNextItem && ( oNextItem != oHoverItem ))
						{
							var oNextHoverPanel = GetHostPanelEl( oNextItem );
							DoOnMouseOut( oHoverItem, oEv, false,true);
							if( oNextHoverPanel != oHoverPanel )
							{
								DoOnMouseOut( oHoverPanel, oEv, false, true);
								DoOnMouseOver( oNextHoverPanel, oEv, false, true);
							}
							DoOnMouseOver( oNextItem, oEv, false, true);
						}	
					}
				}
			}
		}		
	}
	
	function GetNextForeparentItem( oChildItem, bNext, bVert )
	{
		var oRes = null;
		var oHostPan = GetHostPanelEl( oChildItem );
		if( bVert == IsPanelLayoutVert( oHostPan ) )
		{
			var nIndex = m_oItemMnemonics[ oChildItem.id ].nIndex;
			var nItemCount = GetMnemonicsCount( oHostPan ) ;
			var nNextIndex = 0;
			if( bNext )
			{
				nNextIndex = ( nIndex + 1 < nItemCount ) ? ( nIndex +1 ) : 0 ;
			}
			else
			{						
				nNextIndex = ( nIndex - 1 < 0 ) ? ( nItemCount - 1 ) : ( nIndex -1 );
			}
			oRes = ( nIndex == nNextIndex )? null : GetItem( oHostPan, nNextIndex );
			}
			else
			{
				if( !IsRootContainer( oHostPan ) )
				{
					var oParItem = GetParentItemEl( oHostPan );
					oRes = GetNextForeparentItem( oParItem, bNext, bVert );
			}
		}
		return oRes;
	}
	
	function GetPreviousChildItem( oItem )
	{
		var oRes = oItem;
		var nIndex = m_oItemMnemonics[ oItem.id ].nIndex;
		var oPanel = GetHostPanelEl( oItem );
		var oParItem = GetItem( oPanel, nIndex -1 );
		if( nIndex > 0 )
		{
			oRes = GetLastChildItem( oParItem );  
		}
		
		return oRes;
	}
	
	function GetNextItem( oItem, bIncludeChild )
	{
		var oRes = null;
		var oPanel = GetHostPanelEl( oItem );
		var nIndex = m_oItemMnemonics[ oItem.id ].nIndex;

		var oSubMenu = GetSubMenuEl( oItem );
		if( bIncludeChild && oSubMenu && GetIsStaticPanel( oSubMenu ) )
		{
			oRes = GetItem( oSubMenu, 0);
		}
		else if( nIndex + 1 < GetMnemonicsCount( oPanel ) )
		{
			oRes = GetItem( oPanel, nIndex + 1 );
		}
		else if( !IsRootContainer( oPanel ) )
		{
			var oParentItem = GetParentItemEl( oPanel );
			oRes = GetNextItem( oParentItem, false );
		}
		else
		{
			oRes = GetItem( m_oRootPanEl, 0 );
		}
		
		return oRes;		
	}
	
	function GetLastChildItem( oItem )
	{
		var oRes = oItem;
		
		var oSubMenu = GetSubMenuEl( oItem );
		if( oSubMenu && GetIsStaticPanel( oSubMenu )&& ( GetMnemonicsCount( oSubMenu ) > 0 ) )
		{		
			oRes = GetLastChildItem( GetItem( oSubMenu, GetMnemonicsCount( oSubMenu )- 1 ));
		}
		
		return oRes;
	} 
	
	function GetLastItem()
	{
		var oLastRootItem = GetItem( m_oRootPanEl, GetMnemonicsCount( m_oRootPanEl ) - 1 );
		var oRes = GetLastChildItem( oLastRootItem );
		return oRes;				
	}
	
	/////////////////////////////////////////////////////////////////////////
	// visualizing

	function HiliteHover( oEl, bIsScrollerEl )
	{
		if ( ( NeedToHilite( oEl ) || bIsScrollerEl ) && 
			!(c_nStateHover == oEl.State || c_nStateActive == oEl.State ) )
		{
			oEl.State = c_nStateHover;
			m_oHoverItem = oEl;
			
			UpdateItemLook( oEl, c_nStateHover, bIsScrollerEl );			
		}
	}

	function UnHiliteHover( oEl, bIsScrollerEl )
	{
		if( bIsScrollerEl )
		{
			ResetItemState( oEl, bIsScrollerEl );
		}
		else
		{
			m_oHoverItem = null;
			var oSubEl = GetSubMenuEl( oEl );
			if( oSubEl && ( oSubEl.IsExpanded || ( oSubEl.IsExpanding && null == oSubEl.TimerExpand ) ) )
			{
				HiliteExpanded( oEl );
			}
			else
			{		
				ResetItemState( oEl );
			}
		}
	}

	function HiliteExpanded( oEl )
	{
		if (NeedToHilite( oEl ))
		{
			oEl.State = c_nStateExpanded;
			if( m_oHoverItem == oEl )
			{
				m_oHoverItem = null;
			}
			
			UpdateItemLook( oEl, c_nStateExpanded );
		}
	}
	
	function UnHiliteExpanded( oEl )
	{
		if( m_oHoverItem == oEl )
		{
			m_oHoverItem = null;
		}
		ResetItemState( oEl );
	}
	
	function ResetItemState( oEl, bIsScrollerEl )
	{
		if (NeedToHilite( oEl ) || bIsScrollerEl )
		{
			oEl.State = c_nStateNone;
			
			UpdateItemLook( oEl, c_nStateNone, bIsScrollerEl );
		}		
	}
	
	function NeedToHilite( oEl )
	{
		var bRes = (!IsItemContainer( oEl )/* && !IsItemDisabled( oEl )*/ );
		return bRes;
	}

	function MarkPanelHover( oEl, bVal )
	{
		if (IsItemContainer( oEl ))
		{
			oEl.IsHover = bVal;
			m_oHoverPanel = bVal ? oEl : null;
	//		alert( oEl.id +"__"+ bVal  );
		}
	}
	
	/////////////////////////////////////////////////////////////////////////
	// positioning
	
	function SetSubMenuPosition( oEl, oHostPanel )
	{
		var bPosUp = false, bPosLeft = false;
		var oSubEl = GetSubMenuEl( oEl );
		if (oSubEl)
		{
			var oSl = GetSlideEls( oSubEl);
			var oHostEl = oSl.oHostEl;			
			
			var nSubPanOffsetX = 0;
			var nSubPanOffsetY = 0;
			if (oHostPanel)
			{
				var n;
				var sX = DOM.GetAttribute( oHostPanel, c_sAttrSubPanOffsetX );
				if (sX && (n = parseInt( sX, 10 )))
				{
					nSubPanOffsetX = n;
				}
				var sY = DOM.GetAttribute( oHostPanel, c_sAttrSubPanOffsetY );
				if (sY && (n = parseInt( sY, 10 )))
				{
					nSubPanOffsetY = n;
				}
			}
			
			var bRTL = IsMenuRightToLeft();
			
			var nL=0;
			var nT=0;
			var oParHost = GetHostPanelEl( oEl );
			
			var oOffsetEl = null;
			if( !self.GetUseFrames() ||( GetIsStaticPanel( oParHost) && !IsContextMenu() ))
			{
				// Get toplevel document element (BODY for back-CSS/HTML for CSS1)
				var oTopmostEl = DOM.GetTopmostLayoutEl();
				// Calculates offset in pixels of oEl relatively to toplevel document element
				oOffsetEl = DOM.GetOffset( oEl, oTopmostEl );
			}
			else
			{
				var oOffsetEl = DOM.GetOffset( oEl, oParHost );
				var oParSubEl = GetHostPanelEl( oEl );
				if( oParSubEl && ( IsContextMenu() || !IsRootContainer( oParSubEl ) ) )
				{
					var oOffsetEl = DOM.GetOffset( oEl, oParSubEl );
					if( oParSubEl.m_nOffsetLeft )
					{
						oOffsetEl.x += oParSubEl.m_nOffsetLeft;
					}
					if( oParSubEl.m_nOffsetTop )
					{
						oOffsetEl.y += oParSubEl.m_nOffsetTop;
					}
				}
			}
		
			nL = oOffsetEl.x ; 
			nT = oOffsetEl.y ;
			// Adjustment for RTL (nothing is done if LTR)
			oOffsetEl.x += DOM.GetLostOffsetLeft();

			// Calculates actual subpanel offset including autolayout and parent item width/height
			var nSupElHeight = oSubEl.offsetHeight;
			var nSupElWidth = oSubEl.offsetWidth;
			oXY = DOM.CalculateSubpanelOffset( oOffsetEl, oEl.offsetWidth, oEl.offsetHeight, nSupElWidth, nSupElHeight, nSubPanOffsetX, nSubPanOffsetY, IsPanelLayoutVert( oEl ), bRTL, false);
			if( oXY.x < 0 )
			{
				bPosLeft = true;	
			}
			if( oXY.y < 0 )
			{
				bPosUp = true;	
			}
			nL += oXY.x;
			nT += oXY.y; 
			var oHostStl = oHostEl.style;
			oHostStl.left = nL + "px";
			oHostStl.top = nT + "px";
			oSubEl.m_nOffsetLeft = nL;
			oSubEl.m_nOffsetTop = nT;
		}
		return { IsLeft: bPosLeft, IsTop: bPosUp }
	}
	
	function SetContextMenuPosition( oEv, oHostPanel, x, y )
	{
		var bRes = false;
		var bPosLeft = false;

		do
		{
			var nL = 0, nT = 0;
			var oOffsetXY = null;
			if( oEv &&( null != oEv.clientX )&&( null != oEv.clientY ) )
			{
				oOffsetXY= DOM.GetOffsetCoordsEvent( oEv );
				nL += oOffsetXY.x - DOM.GetLostOffsetLeft();
				nT += oOffsetXY.y;
			}
			else
			{
				if( ( null != x )&&( null != y ) )
				{
					oOffsetXY = [];
					oOffsetXY.x = x;
					oOffsetXY.y = y;
					nL += x;
					nT += y;
				}
				else
				{
					break;
				}
			}
						
			var bRTL = IsMenuRightToLeft() ;
			var oXY = DOM.CalculateSubpanelOffset( oOffsetXY, 0, 0, m_oRootPanEl.offsetWidth, m_oRootPanEl.offsetHeight, 0, 0, true, bRTL, true);
			nL += oXY.x;
			nT += oXY.y;
						
			if( oXY.x < 0 )
			{
				bPosLeft = true;
			}
			
			oHostPanel.style.left = nL + "px";
			oHostPanel.style.top = nT + "px";
			m_oRootPanEl.m_nOffsetLeft = nL;
			m_oRootPanEl.m_nOffsetTop = nT;
			bRes = true;
		}		
		while( false )
		
		return { IsLeft: bPosLeft, Result: bRes }
	}
	
	function GetPanelHeight( oSubEl )
	{
		var nH = oSubEl.offsetHeight;
		return nH;
	}
	
	function GetPanelWidth( oSubEl )
	{
		var nW = oSubEl.offsetWidth;
		return nW;
	}
		
	/////////////////////////////////////////////////////////////////////////
	// expanding/collapsing
	
	function PrepareExecCollapsing( oEl )
	{
		var oSubEl = GetSubMenuEl( oEl );
		if( oSubEl && oSubEl.IsExpanding && null != oSubEl.TimerExpand )
		{
			CancelExpandStarter( oSubEl );
			oSubEl.IsExpanding = false;
			var oHostEl = GetHostPanelEl( oEl );
			ReSetPinnedPanel( oHostEl );
		}
	}

	function ExecExpanding( oEl, oSubEl, nExpandDelay, bActivateSubMenu )
	{
		if (oSubEl && !IsItemDisabled( oEl ))
		{
			var oPanToPin = GetHostPanelEl( oEl );
			if( oPanToPin.IsExpanding )
			{
				oPanToPin.ItemHover = oEl ;					
			}
			
			if (!oPanToPin.IsExpanding && !oPanToPin.IsCollapsing)
			{
				if(!oSubEl.IsExpanded && !oSubEl.IsExpanding && !GetIsStaticPanel( oSubEl ) )
				{
					if( ( !oSubEl.IsCollapsing ) || !self.GetCollapseCascaded() )
					{
						SetPinnedPanel( oPanToPin );
					}
						 
					if( self.GetScrollingEnabled() )
					{
						var oScrollPanel = GetScrollEls( oSubEl ).oScrollPanelEl;
						var oScrollTable = DOM.GetFirstChild( oScrollPanel);
						var nSubElExtHeight = DOM.GetElementExtWidth( oSubEl, true )+DOM.GetElementExtWidth( oSubEl, false );
						oSubEl.style.width = oScrollTable.offsetWidth + nSubElExtHeight - DOM.GetWidthDifference( oSubEl ) +"px";

						SetupPanelHeight( oSubEl );			
					}
			
					var oDrawing = SetSubMenuPosition( oEl, oPanToPin );

					// expand
					oSubEl.IsExpanding = true;

					// expand submenu horizontally if this panel is vertical
					var bExpVert = !IsPanelLayoutVert( oEl );
					
					var bUsualPosition = ( bExpVert && !oDrawing.IsTop )||( !bExpVert && !oDrawing.IsLeft )
					
					if( !oSubEl.IsCollapsing )
					{
						InvokeExpanding( oSubEl, oPanToPin, bExpVert, bUsualPosition, nExpandDelay, false, bActivateSubMenu );
					}
					else
					{						
						oSubEl.IsCollapsing = false;
						InvokeExpanding( oSubEl, oPanToPin, bExpVert, bUsualPosition, 0, false, bActivateSubMenu );						
					}
				}				
			}
		}
	}	
	
	function ExecCollapsing( oEl, nCollapseDelay, bCollapseParent )
	{
		if (oEl)
		{
			var oSubEl = null;
			var oPanToUnPin = null;			

			if (IsItemContainer( oEl ))
			{
				if (!IsRootContainer( oEl ))
				{
					oSubEl = oEl;
					var oParEl = GetParentItemEl( oSubEl );
					oPanToUnPin = GetHostPanelEl( oParEl );
				}
				else
				{
					if( oEl.CanCollapse )
					{
						oSubEl = oEl;
					}
				}				
			}
			else
			{
				oSubEl = GetSubMenuEl( oEl );
				oPanToUnPin = GetHostPanelEl( oEl );
			}		
			
			if ( oSubEl && !oSubEl.IsCollapsing && !oSubEl.IsHover && 
				!IsPanelPinned( oSubEl ) && ( !GetIsStaticPanel( oSubEl )|| oSubEl.CanCollapse ) &&
				(oSubEl.IsExpanded || oSubEl.IsExpanding))
			{
				InvokeCollapsing( oSubEl, oPanToUnPin, nCollapseDelay, bCollapseParent );
			}
		}
	}	
	
	function OnContextMenu( oEv )
	{
		DoShowContextMenu( null ,null , oEv, null );
		DOM.EventCancel( oEv );
	}
	
	function StartCollapse( oEl )
	{
		CancelCollapseStarter( oEl );
		ExecCollapsing( oEl, 0, true );
	}
	
	function DoCollapse()
	{	
		m_bNoClickExpand = false;
		if( null != m_oHoverItem )
		{
			DoOnMouseOut( m_oHoverItem, null, false, true );
		}
		if( null != m_oPreviousExpandedPanel )
		{		
			if( m_oPreviousHoverPanel )
			{
				MarkPanelHover( m_oPreviousHoverPanel, false );
			}
			if(m_oPreviousExpandedPanel)
			{
				MarkPanelHover( m_oPreviousExpandedPanel, false );
			}
			StartCollapse( GetIsStaticPanel( m_oPreviousExpandedPanel ) ? m_oRootPanEl : m_oPreviousExpandedPanel );
		}
	}
	
	function RestartMenuState()
	{
		for (var i = 0; i < m_aPanelCache.length; ++i)
		{
			var oPanel = m_aPanelCache[i];
			var oHostPan = GetSlideEls( oPanel ).oHostEl;
		
			CancelCollapseStarter( oPanel );
			CancelExpandStarter( oPanel );
			if( !IsRootContainer( oPanel ) )
			{
				var oPar = GetParentItemEl( oPanel );
				UnHiliteExpanded( oPar );
				var oHost = GetHostPanelEl( oPar );
				UnPinPanel( oHost );
			}
			oPanel.IsExpanding		= false;
			oPanel.IsExpanded		= false;
			oPanel.IsCollapsing		= false;
			CSS.SetVisible( oHostPan, false );
		}
	}
	
	function DoCollapseRootPanel()
	{		
		m_oRootPanEl.CanCollapse = true;
		DoCollapse();		
	}	

	function InvokeExpanding( oSubEl, oPanToPin, bVert, bUsualPosition, nExpandDelay, bIsExpandingRootEl, bActivateSubMenu )
	{
		oSubEl.ExpandingInited = false;
		oSubEl.SlideVertical = bVert;
		oSubEl.UsualPosition = bUsualPosition;

		// Set zIndex of panel to expand
		var oSl = GetSlideEls( oSubEl );
		var oHostEl = oSl.oHostEl;
		if( IsRootContainer( oSubEl ) )
		{
			CSS.SetZIndex( oHostEl, c_nPanelZIndex );
		}
		else
		{
			CSS.SetZIndex( oHostEl, c_nTopPanelZIndex );
		}

		m_oCurExpandingParams = 
		{
			oSubEl				: oSubEl, 
			oPanToPin			: oPanToPin,
			bIsExpandingRootEl	: bIsExpandingRootEl,
			bActivateSubMenu	: bActivateSubMenu
		};
	
		function FnProxy()
		{		
			ExecExpandStep();			
		}
		
		if( 0 == nExpandDelay )
		{
			ExecExpandStep();
		}
		else
		{
			var nExpandTimer = setTimeout( FnProxy, nExpandDelay );
			oSubEl.TimerExpand = nExpandTimer;
		}
	}

	function InvokeCollapsing( oSubEl, oPanToUnPin, nCollapseDelay, bCollapseParent )
	{		
		oSubEl.CollapsingInited = false;
		
		var oParams = 
		{
			oSubEl			: oSubEl,
			oPanToUnPin		: oPanToUnPin,
			bCollapseParent : bCollapseParent
		};

		function FnProxy()
		{	
			oSubEl.IsCollapsing = true;
			ExecCollapseStep( oParams );
		}

		if( nCollapseDelay == 0 )
		{
			oSubEl.IsCollapsing = true;
			ExecCollapseStep( oParams );
		}
		else
		{
			var nCollapseTimer = setTimeout( FnProxy, nCollapseDelay );
			oSubEl.TimerCollapse = nCollapseTimer;
		}
	}	
	 
	function PrepareExpandWithFilter( oSubEl )
	{
		SetPanelTransitionReady( oSubEl, true );		
	}
	
	function PrepareCollapseWithFilter( oSubEl )
	{
		SetPanelTransitionReady( oSubEl, false );
	}
	function SetPanelTransitionReady( oSubEl, bExpand )
	{
		if( self.GetScrollingEnabled() )
		{
			var oScrollEls = GetScrollEls( oSubEl );
			var oScrollUpEl = oScrollEls.oScrollUpEl;
			var oScrollDownEl = oScrollEls.oScrollDownEl;
			var oScrollPanelEl = oScrollEls.oScrollPanelEl;
			
			CSS.SetVisible( oScrollDownEl, false );
			CSS.SetVisible( oScrollUpEl, false );
			oSubEl.style.overflow = "hidden";
			oScrollPanelEl.style.position="static";
			
			oSubEl.scrollTop = bExpand ? 0 : oScrollPanelEl.ClipScrollTop;
		}
	}
	
	function ExecExpandStep()
	{	
		var oParams = m_oCurExpandingParams;
		
		var oSubEl = oParams.oSubEl;
		
		if (!oSubEl.IsExpanding ||( null == DOM.GetParentEl( oSubEl ) ))
		{
			FinalizeExpand( oSubEl );
			return;
		}
		
		var oPanToPin = oParams.oPanToPin;
		var bIsExpandingRootEl = oParams.bIsExpandingRootEl;
		var oChildStl = oParams.oChildStl;
		
		var oSl = GetSlideEls( oSubEl );
		var oChildEl = oSl.oChildEl;
		var oHostEl = oSl.oHostEl;
		
		var oHostOffset = oHostEl.m_oInitOffset;				
		
		var nWidth = oParams.nWidth;
		var nHeight = oParams.nHeight;
		
		var bVert = oSubEl.SlideVertical;
		var bUsualPosition = oSubEl.UsualPosition;

		if( !oSubEl.ExpandingInited )
		{	
		    if( !bIsExpandingRootEl && m_oPreviousExpandedPanel && m_oPreviousExpandedPanel != oPanToPin )
			{
				var oItem = GetParentItemEl( m_oPreviousExpandedPanel );
				StartCollapse( m_oPreviousExpandedPanel );
			}
				
			m_oPreviousExpandedPanel = oSubEl;
			
			// First pass
			oSubEl.TimerExpand		= null;				
			oSubEl.IsCollapsing		= false;
			oSubEl.ExpandingInited	= true;
			oSubEl.Expanding		= true;			
			
			if( m_nExpandTimer )
			{
				clearTimeout( m_nExpandTimer );
			}			
						
			CSS.SetVisible( oSubEl, true );
			if( self.GetUseFrames() )
			{
				oHostEl.m_oInitOffset = 
				{
					x : oHostEl.offsetLeft,
					y : oHostEl.offsetTop
				}
				oHostOffset = oHostEl.m_oInitOffset;
				if( bVert)
				{
					oHostEl.height = "0px";
					oHostEl.width = oSubEl.offsetWidth + "px";
				}
				else
				{
					oHostEl.height = oSubEl.offsetHeight + "px";
					oHostEl.width = "0px";					
				}
			}
			else
			{
				oHostEl.style.width = oChildEl.offsetWidth+"px";
			}
			
			nWidth = oParams.nWidth = oSubEl.offsetWidth;
			nHeight = oParams.nHeight = oSubEl.offsetHeight;
			
			oChildStl = oParams.oChildStl = oChildEl.style;			
			
			oParams.nIter = 0;
			// set sliding child initially collapsed
			if( self.GetUseFrames() )
			{
				if (bVert)
				{				
					oHostEl.style.height = "0px";
					if(bUsualPosition )
					{
						oChildStl.top = ( bUsualPosition ? (-nHeight) : nHeight ) + "px";
					}
					else
					{
						oChildStl.top = "0px";
						oHostEl.style.top = oHostOffset.y + nHeight + "px";
					}
					
				}
				else
				{
					oHostEl.style.width = "0px";
					if(bUsualPosition )
					{
						oChildStl.left = -nWidth + "px";
					}
					else
					{
						oChildStl.left = "0px";
						oHostEl.style.left = oHostOffset.x + nWidth + "px";
					}
				}
			}
			else
			{
				if (bVert)
				{				
					oChildStl.top = ( bUsualPosition ? (-nHeight) : nHeight ) + "px";
				}
				else
				{
					oChildStl.left = ( bUsualPosition ? (-nWidth) : nWidth ) + "px";
				}
			}
			
			//stop collapse filter
			if( GetIsCollapseTransition() )
			{
				CSS.StopTransFilter( oSubEl );
			}
			//for scroll
			if( self.GetScrollingEnabled() )
			{
				PrepareScroll( oSubEl );		
			}
			
			// Expand transition
			if( GetIsExpandTransition() || self.GetUseFrames() )
			{
				if( !IsRootContainer( oSubEl ) )
				{
					PrepareExpandWithFilter( oSubEl );
				}
				var sExpandTransFilter = CSS.GetTransitionFilter( self.GetExpandTransition() );
				CSS.TransExpand( oSubEl, self.GetExpandDuration(), sExpandTransFilter );
			}			
			
			// make expanding panel visible
			CSS.SetVisible( oHostEl, true );
						
		}

		var nDim = bVert ? nHeight : nWidth;
		var oSlPar = GetSlideParams( nDim, ++oParams.nIter, true );
		
		var nPos = oSlPar.nDimCur - nDim + 1;

		if (nPos < 0)
		{			
			if( self.GetUseFrames() )
			{
				if (bVert)
				{
					oHostEl.style.height = nHeight + nPos + "px";
					if( bUsualPosition )
					{
						oChildStl.top = nPos + "px";
					}
					else
					{
						oHostEl.style.top = oHostOffset.y - nPos + "px";
					}						
				}
				else
				{					
					oHostEl.style.width = nWidth + nPos + "px";
					if( bUsualPosition )
					{
						oChildStl.left = nPos + "px";
					}
					else
					{
						oHostEl.style.left = oHostOffset.x - nPos + "px";
					}				
				}
			}
			else
			{
				if (bVert)
				{
					oChildStl.top = ( bUsualPosition ? nPos : (-nPos) ) + "px";
				}
				else
				{
					oChildStl.left = ( bUsualPosition ? nPos : (-nPos) ) + "px";
				}
			}
			
			if( m_nExpandTimer )
			{
				clearTimeout( m_nExpandTimer );
			}
			m_nExpandTimer = setTimeout( ExecExpandStep, oSlPar.dInt );
		}
		else
		{
			oChildStl.top = "0px";
			oChildStl.left = "0px";
			if( self.GetUseFrames() )
			{
				oHostEl.style.height = oSubEl.offsetHeight + "px";
				oHostEl.style.width = oSubEl.offsetWidth + "px";
				if( !bUsualPosition )
				{
					if(bVert)
					{
						oHostEl.style.top = oHostOffset.y + "px";
					}
					else
					{
						oHostEl.style.left = oHostOffset.x + "px";
					}
				}
			}
					
			if( self.GetScrollingEnabled() && ( GetIsExpandTransition() || self.GetUseFrames() ) && !IsRootContainer( oSubEl ) )
			{
				var oScrollEls = GetScrollEls( oSubEl );
				var oScrollUpEl = oScrollEls.oScrollUpEl;
				var oScrollDownEl = oScrollEls.oScrollDownEl;
				var oScrollPanelEl = oScrollEls.oScrollPanelEl;
				
				oSubEl.style.overflow= "";
				oScrollPanelEl.style.position = "absolute";
				
				SetupPanelHeight( oSubEl );			
				
				if( oScrollPanelEl.ClipHeight < oScrollPanelEl.offsetHeight )
				{
					CSS.SetVisible( oScrollDownEl, true );
				}
			
			}
			
			// stop expanding
			oSubEl.IsExpanded = true;

			FinalizeExpand( oSubEl );
			
			var oSubItemHover = oSubEl.ItemHover;
			if( oSubItemHover )
			{
				var oSubMenuEl = GetSubMenuEl( oSubItemHover );
				if( oSubMenuEl )
				{
					CancelCollapseStarter( oSubMenuEl );
					ExecExpanding( oSubItemHover, oSubMenuEl, self.GetExpandDelay(), false );					
				}
			}	
			
			oSubEl.ItemHover = null;
			var oParentItem = IsRootContainer( oSubEl ) ? null : GetParentItemEl( oSubEl );
			if( oParams.bActivateSubMenu && ( GetMnemonicsCount( oSubEl ) > 0 ) && ( ( null == m_oHoverItem )||( oParentItem == m_oHoverItem  ) ) )
			{
				DoOnMouseOut( oParentItem, null, false, false);
				var oParentPanel = GetHostPanelEl( oParentItem );
				if( oSubEl != oParentPanel )
				{
					DoOnMouseOut( oParentPanel, null, false, false);				
					DoOnMouseOver( oSubEl, null, false, false );
				}
				var oItem = GetItem( oSubEl, 0 );
				DoOnMouseOver( oItem, null, false, false );
			}			
		}
	}

	function ExecCollapseStep( oParams )
	{
		var oSubEl = oParams.oSubEl;
		var oPanToUnPin = oParams.oPanToUnPin;
		
		var oChildStl = oParams.oChildStl;
		var bCollapseParent = oParams.bCollapseParent;
		if( !oSubEl.IsCollapsing ||( null == DOM.GetParentEl( oSubEl ) ) )
		{
			return;
		}
		
		var nHeight = oParams.nHeight;
		var nWidth = oParams.nWidth;
				
		var oSl = GetSlideEls( oSubEl );
		var oChildEl = oSl.oChildEl;
		var oHostEl = oSl.oHostEl;
		var oHostOffset = oHostEl.m_oInitOffset;
		
		var bVert = oSubEl.SlideVertical;
		var bUsualPosition = oSubEl.UsualPosition;

		if (!oSubEl.CollapsingInited)
		{
			if( m_oPreviousExpandedPanel == oSubEl )
			{
			   m_oPreviousExpandedPanel = ( oPanToUnPin && GetIsStaticPanel( oPanToUnPin ) && !IsContextMenu() ) ? null : oPanToUnPin;	
			}
					
			// First pass
			oSubEl.IsExpanding		= false;
			oSubEl.IsExpanded		= false;
			oSubEl.IsCollapsing		= true;
			oSubEl.CollapsingInited = true;
			oSubEl.TimerCollapse	= null;
						
			if( oSubEl.TimerCollapseStep )
			{
				clearTimeout( oSubEl.TimerCollapseStep );
			}
			
			oSubEl.ItemHover = null;
			
			var oSl = GetSlideEls( oSubEl );
			var oHostEl = oSl.oHostEl;
			var oChildEl = oSl.oChildEl;
			
			CSS.SetVisible( oSubEl, true );
			CSS.SetZIndex( oHostEl, c_nPanelZIndex );

			//stop expand filter
			if( GetIsExpandTransition() )
			{
				CSS.StopTransFilter( oSubEl );
			}
			// Collapse transition
			if( GetIsCollapseTransition()|| self.GetUseFrames() )
			{
				if( !IsRootContainer( oSubEl ) )
				{
					PrepareCollapseWithFilter( oSubEl );
				}
				var sCollapseTransFilter = CSS.GetTransitionFilter( self.GetCollapseTransition() );
				CSS.TransCollapse( oSubEl, self.GetCollapseDuration(), sCollapseTransFilter );
			}

			if( !IsRootContainer( oSubEl ) )
			{
				var oPar = GetParentItemEl( oSubEl );
				var bCollapseParent = oParams.bCollapseParent;
				if( bCollapseParent ) 
				{
					UnHiliteExpanded( oPar );
				}
			}
			
			// Invoke parent panel collapsing
			var bCollapseParent = oParams.bCollapseParent;
			if( !self.GetCollapseCascaded() && !IsRootContainer( oSubEl ) )
			{
				ReSetPinnedPanel( oPanToUnPin );
			
				var oItemEl = GetParentItemEl( oPanToUnPin );
				if( GetIsStaticPanel( oPanToUnPin ) )
				{					
					oPanToUnPin = GetRootPanelEl();						
				}
				if( bCollapseParent &&( ( IsRootContainer( oPanToUnPin ) && oPanToUnPin.CanCollapse ) ||( oItemEl && ( c_nStateHover != oItemEl.State ) ) ) )
				{					
					ExecCollapsing( oPanToUnPin, 0, bCollapseParent );
				}
			}			

			oChildStl = oParams.oChildStl = oChildEl.style;

			nHeight = oParams.nHeight = oChildEl.offsetHeight;
			nWidth = oParams.nWidth = oChildEl.offsetWidth;
			
			oParams.nIter = 0;
			
			// set sliding child initially expanded
			if( self.GetUseFrames() )
			{
				if (bVert)
				{
					oHostEl.style.height = oChildEl.offsetHeight + "px";
				}
				else
				{
					oHostEl.style.width = oChildEl.offsetWidth + "px";
				}
			}
			else
			{
				if (bVert)
				{
					oChildStl.top = "0px";
				}
				else
				{
					oChildStl.left = "0px";
				}
			}
			
		}

		var nDim = bVert ? nHeight : nWidth;
		var oSlPar = GetSlideParams( nDim, ++oParams.nIter, false );		

		var nPos = -oSlPar.nDimCur;

		if (nDim + nPos > 0)
		{
			if( self.GetUseFrames() )
			{
				if (bVert)
				{
					oHostEl.style.height = ( nHeight + nPos ) + "px";
					if( bUsualPosition )
					{
						oChildStl.top = nPos + "px";
					}
					else
					{
						oHostEl.style.top = oHostOffset.y - nPos + "px"; 
					}
				}
				else
				{
					oHostEl.style.width = ( nWidth + nPos ) + "px";
					if( bUsualPosition )
					{
						oChildStl.left = nPos + "px";
					}
					else
					{
						oHostEl.style.left = oHostOffset.x - nPos + "px";
					}
				}
			}
			else
			{
				if (bVert)
				{
					oChildStl.top = ( bUsualPosition ? nPos : (-nPos) ) + "px";
				}
				else
				{
					oChildStl.left = ( bUsualPosition ? nPos : (-nPos) ) + "px";
				}
			}
			

			function FnProxy()
			{
				ExecCollapseStep( oParams );
			}
			oSubEl.TimerCollapseStep = setTimeout( FnProxy, oSlPar.dInt );
		}
		else
		{
			// make expanding panel hidden
			var oSl = GetSlideEls( oSubEl );
			var oHostEl = oSl.oHostEl;
			CSS.SetVisible( oHostEl, false );
			
			// stop expanding
			oSubEl.CollapsingInited = false;
			oSubEl.IsCollapsing = false;
			oSubEl.IsExpanded = false;
			
			// invoke parent panel collapsing
			var oItemEl = GetParentItemEl( oSubEl );
			if( self.GetCollapseCascaded() && !IsRootContainer( oSubEl ) )
			{
				ReSetPinnedPanel( oPanToUnPin );
				if( bCollapseParent ||( null != m_oHoverItem ) )
				{
					if( !bCollapseParent && oItemEl.State != c_nStateHover )
					{
						UnHiliteExpanded( oItemEl );
					}
					var oParentItemEl = GetParentItemEl( oPanToUnPin );
					if( GetIsStaticPanel( oPanToUnPin ) )
					{					
						oPanToUnPin = GetRootPanelEl();						
					}
					if( ( IsRootContainer( oPanToUnPin ) && oPanToUnPin.CanCollapse ) ||( oParentItemEl && ( c_nStateHover != oParentItemEl.State ) ) )
					{					
						ExecCollapsing( oPanToUnPin, 0, true );
					}
				}
				else
				{
					
					DoOnMouseOver( oPanToUnPin, null, false, false);
					DoOnMouseOver( oItemEl, null, false, false);
				}
			}
			
			if( !self.GetCollapseCascaded() && !IsRootContainer( oSubEl ) && !bCollapseParent )
			{
				if( null == m_oHoverItem )
				{
					DoOnMouseOver( oPanToUnPin, null, false, false);
					DoOnMouseOver( oItemEl, null, false, false);
				}
				else if( oItemEl.State != c_nStateHover )
				{
					UnHiliteExpanded( oItemEl );
				}
			}
		}		
	}

	function FinalizeExpand( oSubEl )
	{
		oSubEl.IsExpanding = false;
	}
	
	function GetSlideEls( oEl )
	{		
		var oChildEl = DOM.GetParentEl( oEl );
		var oHostEl = oChildEl.m_oSlidingHost ? 
			oChildEl.m_oSlidingHost : DOM.GetParentEl( oChildEl );
		
		ASSERT( "menuSlidingHost" == oHostEl.className );
		ASSERT( "menuSlidingChild" == oChildEl.className );

		var oRes = { oHostEl: oHostEl, oChildEl: oChildEl };
		return oRes;
	}
	
	function GetPanelEl( oScrollEl )
	{
		return DOM.GetParentEl( oScrollEl );
	}
	
	function GetIsExpandTransition()
	{
		return (self.TransitionNone != m_nExpandTrans) && CSS.FiltersSupported();
	}

	function GetIsCollapseTransition()
	{
		return (self.TransitionNone != m_nCollapseTrans) && CSS.FiltersSupported();
	}

	function GetSlideParams( nDim, nCurStep, bExp )
	{
		var nIters = parseInt( (bExp ? m_nExpandDuration : m_nCollapseDuration) / c_nSlideMinInt );
		
		var dFract = (nCurStep / nIters);
		var d = 1;
		
		var nType = bExp ? self.GetExpandType() : self.GetCollapseType();
		switch (nType)
		{
			case c_nSlideAcc:
				d = (dFract * dFract);
				break;
			case c_nSlideDec:
				d = Math.sqrt( dFract );
				break;
			case c_nSlideConst:
				d = dFract;
				break;
			case c_nSlideNone:
				if (!bExp)
				{
					d = (nCurStep >= nIters) ? 1 : 0;
				}
				break;
		}

		var nDimCur = Math.round( d * nDim );
		return { nDimCur : nDimCur, dInt : c_nSlideMinInt };
	}

	function CancelCollapseStarter( oSubEl )
	{
		if (oSubEl && !oSubEl.IsCollapsing && null != oSubEl.TimerCollapse)
		{
			clearTimeout( oSubEl.TimerCollapse );
			oSubEl.TimerCollapse = null;
		}
	}
	
	function CancelExpandStarter( oSubEl )
	{
		if( oSubEl && null != oSubEl.TimerExpand && oSubEl.IsExpanding )
		{
			clearTimeout( oSubEl.TimerExpand );
			oSubEl.TimerExpand = null;
		}
	}

	function SetPinnedPanel( oPan )
	{
		if (null == m_oPinnedPanels[ oPan.id ])
		{
			m_oPinnedPanels[ oPan.id ] = 0;
		}
		++m_oPinnedPanels[ oPan.id ];
// DBG("Pin: " + oPan.id + ", rc: " + m_oPinnedPanels[ oPan.id ]);
	}
	
	function ReSetPinnedPanel( oPan )
	{
		if (oPan)
		{
			ASSERT( m_oPinnedPanels[ oPan.id ] > 0, "ERR: null == m_oPinnedPanels[ " + oPan.id + " ]" );
			--m_oPinnedPanels[ oPan.id ];
// DBG("UnPin: " + oPan.id + ", rc: " + m_oPinnedPanels[ oPan.id ]);
		}
	}
	
	function UnPinPanel( oPan )
	{
		if (oPan)
		{
			m_oPinnedPanels[ oPan.id ] = 0;
		}
	}

	function IsPanelPinned( oPan )
	{
		return (m_oPinnedPanels[ oPan.id ] > 0);
	}
	
	function GetIsStaticPanel( oSubEl )
	{
		var bRes = IsRootContainer( oSubEl );
		if( !bRes )
		{
			var oParentNode = DOM.GetParentEl( oSubEl );
			if( oParentNode && ( oParentNode.className == "menuStaticPanelTD" ) )
			{
				bRes = true;
			}
		}
		return bRes;			 
	}
	
	/////////////////////////////////////////////////////////////////////////
	// scrolling
	
	function PrepareScroll( oPanEl )
	{
		if( !IsRootContainer( oPanEl ) )
		{
			var oScrollEls = GetScrollEls( oPanEl );
			var oScrollUpEl = oScrollEls.oScrollUpEl;
			var oScrollDownEl = oScrollEls.oScrollDownEl;
			var oScrollPanelEl = oScrollEls.oScrollPanelEl;
			
			oScrollPanelEl.style.position = "absolute";
			oScrollPanelEl.style.clip = "rect(auto auto auto auto)";
			CSS.SetVisible( oScrollDownEl, false );
			CSS.SetVisible( oScrollUpEl, false );
			
			SetupPanelHeight( oPanEl );
			
			oScrollDownEl.style.width = oScrollPanelEl.offsetWidth - DOM.GetWidthDifference(oScrollDownEl) +"px";
			oScrollUpEl.style.width = oScrollPanelEl.offsetWidth - DOM.GetWidthDifference(oScrollUpEl)+"px";
			
			oScrollPanelEl.ClipScrollTop = 0;
			
			oScrollUpEl.style.top = "auto";
			oScrollPanelEl.style.top = "auto";
				
			oScrollPanelEl.ClipHeight = oPanEl.offsetHeight - DOM.GetElementExtHeight( oPanEl, true ) - DOM.GetElementExtHeight( oPanEl, false );
			if( oScrollPanelEl.ClipHeight < oScrollPanelEl.offsetHeight )
			{
				CSS.SetVisible( oScrollDownEl, true );
				CSS.SetVisible( oScrollUpEl, false );
				
				oScrollDownEl.style.top = oScrollPanelEl.ClipHeight + DOM.GetElementExtHeight(oPanEl, true) - oScrollDownEl.offsetHeight+"px";
				oScrollPanelEl.style.clip = GetClipEl( oScrollPanelEl.ClipScrollTop, oScrollPanelEl.offsetWidth, oScrollPanelEl.ClipHeight, 0);
			}
		}
	}
	
	function GetClipEl( nCutTop, nWidth, nHeight, nCutLeft )
	{
		var sRes = "rect";
		sRes +="(" + nCutTop + "px " + nWidth + "px " + nHeight + "px " +  nCutLeft + "px)";
		return sRes;
	}	
	
	
	function ExecScrollStep( oParams )
	{		
		var bScrollUp			= oParams.bScrollUp;
		var nParamsScrollStep	= oParams.nScrollStep;
		var bScrollNext			= oParams.bScrollNext;			
		var oHoverScroller		= oParams.oScrollingEl;		
		
		if( oHoverScroller )
		{
			if( oHoverScroller.IsScrolling )
			{
				var oPanEl = GetPanelEl( oHoverScroller );
				if( null!= oPanEl )
				{				
				    var oScrollEls = GetScrollEls( oPanEl );
				    var oScrollPanEl = oScrollEls.oScrollPanelEl;
				    var	oScrollDownEl = oScrollEls.oScrollDownEl;
				    var	oScrollUpEl = oScrollEls.oScrollUpEl;
				    var oInactiveScroller = bScrollUp ? oScrollDownEl : oScrollUpEl;
				    var nScroll = bScrollUp ? oScrollPanEl.ClipScrollTop : ( oScrollPanEl.offsetHeight - oScrollPanEl.ClipHeight ) ;
    				
				    if( null != oPanEl.ScrollTimer )
				    {
					    clearTimeout( oPanEl.ScrollTimer );
				    }
				    if( nScroll > 0 )
				    {
					    var nScrollingStepLength = ( nScroll > nParamsScrollStep ) ? nParamsScrollStep : nScroll;
					    var nScrollingStep = bScrollUp ? ( -nScrollingStepLength ) : nScrollingStepLength;
    					
					    oScrollPanEl.ClipScrollTop += nScrollingStep;
					    oScrollPanEl.ClipHeight += nScrollingStep;
					    oScrollPanEl.style.top = oScrollPanEl.offsetTop - nScrollingStep + "px";
    	
					    CSS.SetVisible( oInactiveScroller, true );
    					
					    if( bScrollNext )
					    {
						    var nScrollStep = DOM.IsClipSlow() ? ( 2*c_nScrollingStep ) : c_nScrollingStep;
						    oParams = 
						    {
							    bScrollUp		: bScrollUp,
							    nScrollStep		: nScrollStep,
							    bScrollNext		: true,
							    oScrollingEl	: oHoverScroller
						    };

						    function FnProxy()
						    {	
							    ExecScrollStep( oParams );
						    }
						    oPanEl.ScrollTimer = setTimeout( FnProxy, c_nScrollStepDelay );
					    }
				    }
				    nScroll = bScrollUp ? oScrollPanEl.ClipScrollTop : ( oScrollPanEl.offsetHeight - oScrollPanEl.ClipHeight ) ;
				    if( nScroll <= 0 )
				    {
					    oHoverScroller.IsScrolling = false;
					    CSS.SetVisible( oHoverScroller, false );
				    }			
				    oScrollPanEl.style.clip = GetClipEl( oScrollPanEl.ClipScrollTop, oScrollPanEl.offsetWidth, oScrollPanEl.ClipHeight, 0);
			    }
			}
		}
	}
	
	function SetupPanelHeight( oPanEl )
	{		
		if( self.GetScrollingEnabled() && !IsRootContainer( oPanEl ) )
		{
			var uHeight = DOM.GetAttribute( oPanEl, c_sAttrOwnHeight );
			if( uHeight )
			{
				oPanEl.style.height = uHeight;
			}
			else
			{
				oPanEl.style.height = "";
			}
			var oScrollEls = GetScrollEls( oPanEl );
			var oScrollPan = oScrollEls.oScrollPanelEl;				
			var nPanelExtHeight = DOM.GetElementExtHeight( oPanEl, true ) + DOM.GetElementExtHeight( oPanEl, false );
			var nPanelHeight = oPanEl.offsetHeight - nPanelExtHeight;
			if(( nPanelHeight <= 0 )||( nPanelHeight > oScrollPan.offsetHeight ))
			{
				oPanEl.style.height = oScrollPan.offsetHeight + nPanelExtHeight - DOM.GetHeightDifference( oPanEl ) +"px";
			}
			
			var oTopmostEl = DOM.GetTopmostLayoutEl();
			var nDocHeight = oTopmostEl.clientHeight;
			
			if( oPanEl.offsetHeight > nDocHeight )
			{
				oPanEl.style.height = nDocHeight - DOM.GetHeightDifference( oPanEl ) +"px";
			}
		}		
	}
	
	function GetScrollEls( oEl )
	{	
		var oRes = { oScrollUpEl: null, oScrollPanelEl: null, oScrollDownEl: null }	
		
		if( !IsRootContainer( oEl ) )
		{	
			var oScrollEl = DOM.GetChildren( oEl );
			var oScrollUpEl = oScrollEl[0];
			var oScrollPanelEl = oScrollEl[1];
			var oScrollDownEl = oScrollEl[2];
			oRes = { oScrollUpEl: oScrollUpEl, oScrollPanelEl: oScrollPanelEl, oScrollDownEl: oScrollDownEl }
		}
		
		return oRes;
	}

	function DoScrollIntoView( oHoverItem )
	{
		if( oHoverItem )
		{
			var oHoverPanel = GetHostPanelEl( oHoverItem );
			var oScrollEls = GetScrollEls( oHoverPanel );
			var oScrollPanEl = oScrollEls.oScrollPanelEl;
			var	oScrollDownEl = oScrollEls.oScrollDownEl;
			var	oScrollUpEl = oScrollEls.oScrollUpEl;
			
			var nOffsetTop = DOM.GetOffset( oHoverItem, oScrollPanEl ).y - oScrollPanEl.ClipScrollTop ;
	
			var nScrollPanelHeight = oHoverPanel.offsetHeight - DOM.GetElementExtHeight( oHoverPanel, true ) - DOM.GetElementExtHeight( oHoverPanel, false );
			var nNewOffsetTop = nScrollPanelHeight - oScrollDownEl.offsetHeight - oHoverItem.offsetHeight;
			var oParams =null;
			if( nOffsetTop < oScrollUpEl.offsetHeight )
			{
				oScrollUpEl.IsScrolling = true;
				oParams = 
				{
					bScrollUp		: true,
					nScrollStep		: oScrollUpEl.offsetHeight - nOffsetTop,
					bScrollNext		: false,
					oScrollingEl	: oScrollUpEl
				};
			}
			else if( nOffsetTop > nNewOffsetTop )
			{			
				oScrollDownEl.IsScrolling = true;
				var oParams = 
				{
					bScrollUp		: false,
					nScrollStep		: nOffsetTop - nNewOffsetTop,
					bScrollNext		: false,
					oScrollingEl	: oScrollDownEl
				};				
			}
			if( null != oParams )
			{
				ExecScrollStep( oParams );
			}
		}
	}
	
	/////////////////////////////////////////////////////////////////////////
	// actions

	function ProcessItemSelection( oEl, oEv )
	{
		if (!IsItemDisabled(oEl))
		{
			if (!m_sOnClientItemSelect)
			{
				m_sOnClientItemSelect = DOM.GetAttribute( m_oRootEl, c_sOnItemSelect );
			}

			var bGlobalRes = InvokeClientHandler( m_sOnClientItemSelect, oEl, oEv );
			if ( bGlobalRes )
			{
				var sFN = DOM.GetAttribute( oEl, c_sOnItemSelect );
				var bCont = InvokeClientHandler( sFN, oEl, oEv );
				if (bCont)
				{
					var bNavigated = false;					
					var sTarget = DOM.GetAttribute( m_oRootEl, c_sAttrTarget );
					
					if( m_oInitData.ClientOnly || 
						!DOM.GetIsTargetSelf( sTarget ) )
					{
						var sNaviURL = DOM.GetAttribute( oEl, c_sAttrNaviURL );
						bNavigated = DOM.NavigateTo( sNaviURL, sTarget );						
					}
					
					if( !bNavigated )
					{
					    var sItemIdx = DOM.GetAttribute( oEl, c_sItemIdx );
					    if( self.callback )
					    {
					        self.callback( sItemIdx );
					    }
					    else
					    {
						    var sName = DOM.GetAttribute( m_oRootEl, "name" );
						    if (!sName)
							    sName = m_oInitData.ID;							
						    __doPostBack( sName, sItemIdx );
						}
					}
				}
			}
			
			if( IsContextMenu() )
			{
				DoCollapseRootPanel();
			}
			else
			{
				DoCollapse();
			}
		}
	}
	
	function ProcessOnClientMouseOver( oEl, oEv )
	{
		if (!m_sOnClientMouseOver)
		{
			m_sOnClientMouseOver = DOM.GetAttribute( m_oRootEl, c_sOnItemMouseOver );
		}
		InvokeClientHandler( m_sOnClientMouseOver, oEl, oEv );
	}

	function ProcessOnClientMouseOut( oEl, oEv )
	{
		if (!m_sOnClientMouseOut)
		{
			m_sOnClientMouseOut = DOM.GetAttribute( m_oRootEl, c_sOnItemMouseOut );
		}
		InvokeClientHandler( m_sOnClientMouseOut, oEl, oEv );
	}

	function InvokeClientHandler( sFnOnItemSelect, oEl, oEv )
	{
		var bCont = true;
		if (sFnOnItemSelect)
		{
			try
			{
				function fn()
				{
					eval( "bCont=(" + sFnOnItemSelect + ")" );
				}

				var oData = SureGetItemData( oEl );
				oData.Event = oEv;

				fn.call( oData );
				// if function does not return value we do not break execution
				if (null == bCont) bCont = true;						
			}
			catch(e){}
		}
		return bCont;
	}
	
	function SureGetItemData( oEl )
	{
		if (!oEl.m_oSFData)
		{
			var sID		= GetStrAttribute( oEl, c_sAttrClntID );
			var sText	= GetStrAttribute( oEl, c_sAttrClntText );
			var sTooltip= GetStrAttribute( oEl, c_sAttrClntTooltip );
			var sNaviURL= GetStrAttribute( oEl, c_sAttrNaviURL );
			
			var bDisabled= UTIL.IsTrue( DOM.GetAttribute( oEl, c_sAttrIsDisabled ) );
			var bChecked= UTIL.IsTrue( DOM.GetAttribute( oEl, c_sAttrIsChecked ) );
			
			oEl.m_oSFData = 
			{
				ID			: sID,
				Text		: sText,
				Tooltip		: sTooltip,
				Disabled	: bDisabled,
				Checked		: bChecked,
				NavigateURL	: sNaviURL,
				
				HtmlID		: oEl.id,
				Element		: oEl,
				ParentMenu	: self
			}
		}
		return oEl.m_oSFData;
	}
	
	function GetStrAttribute( oEl, sAttr )
	{
		var sVal = DOM.GetAttribute( oEl, sAttr );
		if (!sVal)
			sVal = "";
		return sVal;
	}
	
	/////////////////////////////////////////////////////////////////////////
	// Mnemonics
	function InitMenuMnemonics()
	{
		for( var i = 0; i < m_arrPanelIDs.length; i++ )
		{
			var oPanelID = m_arrPanelIDs[i];
			var oPanelEl = GetOwnEl( oPanelID );
			if( !GetIsStaticPanel( oPanelEl ) )
			{
				InitMnemonics( oPanelEl );			
			}
		}
		InitMnemonics( m_oRootPanEl );
	}
	
	function InitMnemonics( oPan, bStaticPanelMnemonics )
	{
		var sMnemonics = m_aMnemonics[ oPan.id ];
		m_oPanelMnemonics[ oPan.id ] = [];
		
		if( sMnemonics )
		{
			var oPanMnemonic = GetPanelMnemonicsStorage( oPan );
			for( var n = 0; n < sMnemonics.length; n++ )
			{
				var cMnem = sMnemonics.charAt(n);
				if( !oPanMnemonic[ cMnem ] )
				{
					oPanMnemonic[ cMnem ] = {};
					oPanMnemonic[ cMnem ].m_nItemsNoSep = [];
					oPanMnemonic[ cMnem ].HoverItemIndex = -1;
				}
				var oItems = oPanMnemonic[ cMnem ].m_nItemsNoSep;
				var oItem = GetItem( oPan, n );
				if( null == oItem )
				{
					alert( oPan.id +"+"+n );
				}
				m_oItemMnemonics[ oItem.id ]=[];
				var oItemMnemonic = m_oItemMnemonics[ oItem.id ];
				oItemMnemonic.Mnemonic = cMnem;
				oItemMnemonic.nMnemonicIndex = oItems.length;
				oItemMnemonic.nIndex = n;
				oItems[ oItems.length ] = oItem;
				
				if( GetIsStaticPanel( oPan ) )
				{
					var oSubMenu = GetSubMenuEl( oItem );
					if( oSubMenu && GetIsStaticPanel( oSubMenu ) )
					{
						InitMnemonics( oSubMenu );
					}
				}
			}
		}
	}
	
	function GetMnemonicsCount( oPanel )
	{
		var oRes = 0;
		
		var sMnemonics = m_aMnemonics[ oPanel.id ];
		if( sMnemonics )
		{
			oRes = sMnemonics.length;
		}
		
		return oRes;
	}
	
	function GetPanelMnemonicsStorage( oPanel )
	{
		var oRes = GetIsStaticPanel( oPanel ) ? m_oStaticPanelMnemonics : m_oPanelMnemonics[ oPanel.id ];
		return oRes;			
	}
	
	/////////////////////////////////////////////////////////////////////////
	// control DOM

	function InitPanelsStorage()
	{
		var bUseFrames = self.GetUseFrames();
		if( !bUseFrames || !IsContextMenu() )
		{
			m_oRootPanEl = GetRootPanelEl();
			m_aElCache[ m_oRootPanEl.id ] = m_oRootPanEl;
		}
		
		var sRootPanelID = DOM.GetAttribute( m_oRootEl, c_sAttrRootPanelID );
		var sPanParID = m_oInitData.ID + c_sFloatPanelsContainerIDPart;
		var oPanPar = GetOwnEl( sPanParID );
		m_oFloaterEl = oPanPar;

		var aSlidingHosts = DOM.GetChildren( oPanPar );
		for (var i = 0; i < aSlidingHosts.length; ++i)
		{
			var oSlidingHost = aSlidingHosts[i];
			LoadPanel( oSlidingHost );						
		}
		
		function fnPreAfterLoaded()
		{
		    var bRes = ( m_bIsErrorInited ||
		        ( aSlidingHosts.length == m_aPanelCache.length ) );
		    return bRes;
		}
		
		DOM.RegisterOnCreate( AfterLoaded, fnPreAfterLoaded );
	}	
			
	function LoadPanel( oSlidingHost )
	{
	    var bUseFrames = self.GetUseFrames();
	    
	    function fnPreLoad()
	    {
            var bRes = true;
            if( bUseFrames )
            {
                var wndFrame = oSlidingHost.contentWindow;
                bRes = ( wndFrame != null )&&
                    ( wndFrame.document != null ) &&
                    ( wndFrame.document.body != null );
            }
            return bRes;
        }
	        
        function fnLoad()
        {
            if( m_bIsErrorInited )
            {
                return;
            }
            
            if( !fnPreLoad() )
            {
                setTimeout( fnLoad, c_nRepeatLoadInterval );
            }
            else
            {
                LoadPanelStorage( oSlidingHost );
            }
        }
	    
	    fnLoad();
	}	
		
	function LoadPanelStorage( oSlidingHost )
	{
	    var bRes = false;
	    
		var sRootPanelID = DOM.GetAttribute( m_oRootEl, c_sAttrRootPanelID );
	    var bUseFrames = self.GetUseFrames();
	    var oSlidingChild;
		if (bUseFrames)
		{
			var sPanHTML = oSlidingHost.innerHTML;

			var oFWnd = oSlidingHost.contentWindow;
			SetupFrameWindow( oFWnd, m_oFloaterEl.className );
			var oFDoc = oFWnd.document;
			oFDoc.body.innerHTML = sPanHTML;
			oSlidingChild = DOM.GetFirstChild( oFDoc.body );
		}
		else
		{
			oSlidingChild = DOM.GetFirstChild( oSlidingHost );
		}
		oSlidingChild.m_oSlidingHost = oSlidingHost;
		oSlidingHost.style.top = "0px";
		oSlidingHost.style.left = "0px";

		var oPanEl = DOM.GetFirstChild( oSlidingChild );
		if( IsContextMenu() && (oPanEl.id == sRootPanelID ))
		{
			m_oRootPanEl = oPanEl;
		}
		m_aElCache[ oPanEl.id ] = oPanEl;
		m_aPanelCache[ m_aPanelCache.length ] = oPanEl;
		
	    return bRes;
	}

	function SetupFrameWindow( oFWnd, sContStyle )
	{
		DOM.ImportStyles( oFWnd );
		
		var oFBody = oFWnd.document.body;
		oFBody.className = sContStyle;
		
		var oFStl = oFBody.style;
		oFStl.overflow = "hidden";
		oFStl.margin = "0px";
		oFStl.padding = "0px";
		
		oFWnd[m_oInitData.ObjID] = self;
	}	
	
	function InitImagesStorage()
	{
		var aImgs = m_oInitData.Images;
		if (aImgs)
		{
			for (var i = 0; i < aImgs.length; ++i)
			{
				var sImg = aImgs[i];
				DOM.EnsureImg( sImg );
			}
		}		
	}
	
	function OnTimeOutCreate()
	{
	    if( !m_bIsInited )
	    {
	        m_bIsErrorInited = true;
	        alert("Menu frames can not be loaded.");	        
	    }
	}	
	
	function AfterLoaded()
	{
	    if( m_bIsErrorInited )
	    {
	        return;
	    }
	    InitMenuMnemonics();
		DOM.AfterCreate( m_oFloaterEl );
		
		m_bIsInited = true;
	}

	function GetPanelFromStorage( sID )
	{
		return m_aElCache[ sID ];
	}

	function GetRootPanelEl()
	{	
		if( null == m_oRootPanEl )	
		{
			var sID = DOM.GetAttribute( m_oRootEl, c_sAttrRootPanelID );
			m_oRootPanEl = GetOwnEl( sID );
		}
		return m_oRootPanEl;
	}

	function GetItemEl( sID )
	{
		return GetOwnEl( sID );
	}

	function GetOwnEl( sID )
	{		
		var oEl = GetEl( sID, m_oRootEl );
		
		if( oEl == null )
		{
			var bUseFrames = self.GetUseFrames();
			if( bUseFrames )
			{
				for (var i = 0; i < m_aPanelCache.length; ++i)
				{
					oEl = DOM.GetElById( sID, m_aPanelCache[i] );
					if( oEl )
					{
						m_aElCache[ sID ] = null;
						break;
					}
				}
			}
		}
		return oEl;
	}

	function GetSubMenuEl( oEl )
	{
		var oCh = null;

		var sID = DOM.GetAttribute( oEl, c_sAttrSubMenu );
		if (sID)
		{
			oCh = GetOwnEl( sID );
		}
		
		return oCh;
	}
	
	function GetParentItemEl( oSubEl )
	{
		var oPar = null;

		var sPar = DOM.GetAttribute( oSubEl, c_sAttrParentItem );
		if (sPar)
		{
			oPar = GetItemEl( sPar );
			ASSERT( null != oPar );
		}

		return oPar;
	}
	
	function InitPanelItems( oPanel )
	{	
		oPanel.m_nItemsNoSep = [];
		var oTable = oPanel;
		if( self.GetScrollingEnabled() && !GetIsStaticPanel( oPanel ) )
		{
			var oScrollPanEl = GetScrollEls( oPanel ).oScrollPanelEl;
			oTable = DOM.GetFirstChild( oScrollPanEl );	
		}
		
		var bVert = IsPanelLayoutVert( oPanel );
		var oItemParentTRColl = oTable.rows;
		var oItemParColl = bVert ? oItemParentTRColl : oItemParentTRColl[0].cells;
		for( var n = 0; n < oItemParColl.length; n++  )
		{
			var oItemParentNode = bVert ? oItemParColl[ n ].cells[ 0 ] : oItemParColl[n];
			var oItem = DOM.GetFirstChild( oItemParentNode );
			if( c_sAttrValClassSep != DOM.GetAttribute( oItem , c_sAttrItemClass ) )
			{
				oPanel.m_nItemsNoSep[ oPanel.m_nItemsNoSep.length ] = oItem;
			}
		}	
	}	
	
	function GetItem( oParPan, nIndex )
	{
		var oItem = null;	
			
		if( null == oParPan.m_nItemsNoSep )
		{
			InitPanelItems( oParPan );
		}		
		oItem = oParPan.m_nItemsNoSep[ nIndex ];
		
		return oItem;		
	}

	function GetHostPanelEl( oEl )
	{
		var oPar = null;

		var sPar = DOM.GetAttribute( oEl, c_sAttrHostPanel );
		if (sPar)
		{
			oPar = GetOwnEl( sPar );
			if (!oPar)
			{
				// oPar can be null if host panel is static but is searched among dynamic panels,
				// so topmost static panel is returned instead of direct static host panel
				if( !oPar )
				{
					oPar = m_oRootPanEl;
				}
			}
		}
		
		return oPar;
	}

	function GetEl( sID, oPar, bFindInNext )
	{
		var oEl = m_aElCache[ sID ];
		if (!oEl && !(null === oEl))
		{
			oEl = DOM.GetElById( sID, oPar );
			if (!oEl )
			{
				oEl = DOM.GetElById( sID, m_oFloaterEl );
			}
			
			m_aElCache[ sID ] = oEl ? oEl : null;
		}
		return oEl;
	}

	function HasSubMenu( oEl )
	{
		var bRes = (null != GetSubMenuEl( oEl ));
		return bRes;
	}

	function IsInited()
	{
	    var bRes = ( m_bIsInited && m_oRootPanEl );
		return bRes;
	}

	function IsRootContainer( oEl )
	{		
		return (oEl == m_oRootPanEl);
	}	
	
	function IsItemContainer( oEl )
	{
		return UTIL.IsTrue( DOM.GetAttribute( oEl, c_sAttrIsItemCont ) );
	}

	function IsItemDisabled( oEl )
	{
		return UTIL.IsTrue( DOM.GetAttribute( oEl, c_sAttrIsDisabled ) );
	}
	
	function IsPanelLayoutVert( oEl )
	{
		// check if oEl is panel or item
		var oPar = GetHostPanelEl( oEl );
		if (oPar)
		{
			oEl = oPar;
		}

		var sVal = DOM.GetAttribute( oEl, c_sAttrLayout );
		if (!sVal)
		{
			sVal = IsRootContainer( oEl ) ? c_sAttrValLayHorz : c_sAttrValLayVert;
		}
		return (c_sAttrValLayVert == sVal);
	}
	
	function IsMenuRightToLeft()
	{
		return ( m_oRootPanEl.dir == "rtl" );
	}
	
	function IsContextMenu()
	{
		return self.GetContextMenu() != c_nContextMenuNone;
	}

	/////////////////////////////////////////////////////////////////////////
	// looks
	
	function UpdateItemLook( oEl, nState, bIsScrollerEl )
	{
		var sID = oEl.id;

		UpdateImages( oEl, nState, sID );
		UpdateClasses( oEl, nState, sID, bIsScrollerEl );
	}
	
	function UpdateClasses( oEl, nState, sID, bIsScrollerEl )
	{
		UpdatePartClass( oEl, nState );
		UpdatePartClass( oEl, nState, sID + "_CI" );
		UpdatePartClass( oEl, nState, sID + "_I" );
		if( !bIsScrollerEl )
		{
			UpdatePartClass( oEl, nState, sID + "_TI" );
			UpdatePartClass( oEl, nState, sID + "_TT" );
			UpdatePartClass( oEl, nState, sID + "_TA" );
		
			UpdatePartClass( oEl, nState, sID + "_CT" );
//			UpdatePartClass( oEl, nState, sID + "_CA" );
		
			UpdatePartClass( oEl, nState, sID + "_A" );
		}
	}

	function UpdatePartClass( oEl, nState, sChildID )
	{
		var oCh = ( null == sChildID ) ? oEl : GetEl( sChildID, oEl );
		if (oCh)
		{
			CSS.SetLookClass( oCh, nState );
		}
	}
	
	function UpdateImages( oEl, nState, sID )
	{
		var aImgs = DOM.GetElsByTagName( "IMG", oEl );
		for (var n = 0; n < aImgs.length; ++n)
		{
			var oImg = aImgs[ n ];
			CSS.SetImgSrc( oImg, nState, "Img" );
		}
	}

	/////////////////////////////////////////////////////////////////////////
	// utils

	function DetectShortcut( oEv )
	{
		var sRes = "";
		var nKeyCode = oEv.keyCode;
		var bAlt = oEv.altKey, bCtrl = oEv.ctrlKey, bShift = oEv.shiftKey;
		var bFunctionKey = false, bDigitOrLetterKey = false;
		
		if( UTIL.IsFunctionKey( nKeyCode ) )
			bFunctionKey = true;	
		else if ( UTIL.IsDigitOrLetterKey( nKeyCode ) )
			bDigitOrLetterKey = true;

		if ( bFunctionKey || ( ( bAlt || bCtrl || bShift ) && bDigitOrLetterKey ) )
		{
			if( bAlt )
				sRes += "Alt+";
			if( bCtrl )
				sRes += "Ctrl+";
			if( bShift )
				sRes += "Shift+";
			if( bFunctionKey )
				sRes += UTIL.GetFnKeyStr( nKeyCode );
			else
				sRes += String.fromCharCode( nKeyCode );
		}
		return sRes;
	}
	
//	ctor();
}
