var _sfImageCache = [];
var _sfControlsData = [];
function SF_DOMBase( m_oParams )
{
	var self = this;
	var UTIL = m_oParams.UTIL;
	
	var m_fnCreate;
	var m_fnPreCreatePred;
	
	this.TargetSelf = "_self";
	this.TargetBlank = "_blank";
		
	// Enums
	this.EEventNames = 
	{
	 /* abstract */
	}
	
	this.IsIE = function()
	{
	    return false;
	}
	
	this.IsMoz = function()
	{
	    return false;
	}
	
	this.IsOpera = function()
	{
	    return false;
	}

	this.GetOnCreate = function()
	{
		return m_fnCreate;
	}

	this.GetPreCreatePred = function()
	{
		return m_fnPreCreatePred;
	}

	this.RegisterOnCreate = function( fn, fnPred )
	{
		m_fnCreate = fn;
		m_fnPreCreatePred = fnPred;

		if (this.PreCreate())
		{
			PreCreateLoop();
		}
	}	
	
	this.PreCreate = function()
	{
		// overriden
		return true;		
	}

	this.AfterCreate = function()
	{
		// overriden
	}
	
	this.EventCancel = function( oEv )
	{
	}
	
	this.ControlRefresh = function( oScriptObj, sArg )
	{
	    if( oScriptObj && oScriptObj.callback && oScriptObj.enableCallback )
	    {
	        oScriptObj.callback( "refresh_" + sArg );
	    }
	}
	
	this.IsCompleteMouseOut = function( oEl, oEv )
	{
		return true;
	}
	
	this.IsElContaining = function( oEl, oCont )
	{
		return oCont.contains( oEl );
	}
	
	this.SetControlData = function( oEl, oData )
	{
	    _sfControlsData[ oEl.id ] = oData;
	}
	
	this.GetControlData = function( oEl )
	{
	    return _sfControlsData[ oEl.id ];
	}
	
	this.AddAtlasFeatures = function( oEl, fnDisposeHandler )
	{
		oEl.dispose = function()
		{
		    if( fnDisposeHandler )
		    {
		        fnDisposeHandler();	   
		    }
		}

	    // OBSOLETE: used in ATLAS pre September 2006
	    if( !oEl.control )
	    {
	        oEl.control = {};
	    }

	    oEl.control.dispose = oEl.dispose;
		
		oEl.control.get_id = function()
		{
		    return oEl.id;
		}
	}

	this.IsMouseOnEl = function( oEl, oEv )
	{
		var bRes = false;
		
		if( oEl && oEl.tagName &&( null != self.GetParentEl(oEl) ) )
		{
		   var oElRtStl = self.GetRTStyle( oEl );
			if( oElRtStl &&
				( oElRtStl.visibility != "hidden" )&&
				( oElRtStl.display != "none" ) )
			{
				var oOffsetEl = self.GetOffset( oEl, self.GetTopmostLayoutEl() );
				var oOffsetEvent = self.GetOffsetCoordsEvent( oEv );
				var nTop = oOffsetEl.y;
				var nDown = oOffsetEl.y + oEl.offsetHeight;
				var nLeft = oOffsetEl.x;
				var nRight = oOffsetEl.x + oEl.offsetWidth;
				
				var x = oOffsetEvent.x;
				var y = oOffsetEvent.y;
				bRes = ( x < nRight )&&( x > nLeft )&&( y < nDown )&&( y > nTop );
			}
		}
		return bRes;
	}
	
	this.GetEventSrcElement = function( oEv )
	{
		return oEv.srcElement;
	}

	this.IsFloaterDetached = function()
	{
		return false;
	}
	
	// DOM
	this.GetElsByTagName = function( sTag, oCont )
	{
		if (!oCont) oCont = window.document;
		return oCont.getElementsByTagName( sTag );
	}

	this.GetElByTagName = function( sTag, oCont )
	{
		var aEls = this.GetElsByTagName( sTag, oCont );
		return aEls.length > 0 ? aEls[ 0 ] : null;
	}
	
	this.GetFirstChild = function( oEl )
	{
		return oEl.firstChild;
	}

	this.GetChildren = function( oEl )
	{
		return oEl.childNodes;
	}
	
	this.GetChildsByPredicate = function( oEl, fnPred )
	{
	    var oRes = [];
		var oChildren = self.GetChildren( oEl );
		if( oChildren )
		{
			for( var n = 0; n < oChildren.length; ++n )
			{
				var oChild = oChildren[n];
				if( oChild && fnPred( oChild ) )
				{
					oRes[ oRes.length ] = oChild;					
				}
			}
		}
		return oRes;	
	}
	
	this.GetChildsElements = function( oEl )
	{
		function fnPred( oEl )
		{
			var bRes = !!oEl.tagName;
			return bRes;
		}
		return self.GetChildsByPredicate( oEl, fnPred );
	}
	
	this.GetParentEl = function( oEl )
	{
		return oEl.parentNode;
	}
	
	this.RemoveNode = function( oChildNode )
	{
		var oParentEl = oChildNode.parentNode;
		if ( oParentEl )
		{
			oParentEl.removeChild( oChildNode );
		}
	}
	
	this.DestroyTree = function( oEl )
    {
        var oChilds = self.GetChildren( oEl );
        for (var i = oChilds.length - 1; i >= 0; i--) 
        {        
            var oNode = oChilds[i];
            if( oNode.control && oEl.control.dispose )
            {
				oEl.control.dispose();
			}				
            self.DestroyTree( oNode );
        }
        self.RemoveNode( oEl );
    }
	
	this.EnsureImg = function( sURL )
	{
		if (sURL)
		{			
			if (!_sfImageCache[sURL])
			{
				var oImg = new Image();
				oImg.src = sURL;
				_sfImageCache[sURL] = oImg;
			}
			return _sfImageCache[sURL].src;
		}
		return sURL;
	}
	
	// Layout
	this.GetLostOffset = function( oSubEl )
	{
		return null;
	}
	
	this.GetOffset = function( oEl, oCont )
	{
		return null;
	}	
	
	this.GetOffsetCoordsEvent = function ( oEv )
	{
		var nX = 0, nY = 0;
		var oTopmostEl = self.GetTopmostLayoutEl();
		nX += oEv.clientX + oTopmostEl.scrollLeft;
		nY += oEv.clientY + oTopmostEl.scrollTop;

		return { x: nX, y: nY };
	}
	
	this.GetTopmostLayoutEl = function()
	{
		var oEl = document.body;
		return oEl;
	}
	
	this.GetScrollbarWidth = function( oEl, bHorizontal )
	{
		return 16;
	}
	
	this.IsClipSlow = function()
	{
		return false;
	}
	
	this.GetRTStyle = function( oEl )
	{
		return oEl.style;
	}
	
	this.GetElementExtWidth = function( oEl, bLeft )
	{
	}

	this.GetElementExtHeight = function( oEl, bTop )
	{
	}
	
	this.GetLostOffsetLeft = function()
	{
		return 0;
	}
	
	this.GetElementWidthMargin = function( oEl, bLeft )
	{
		return 0;				
	}
	
	this.GetElementHeightMargin = function( oEl, bTop )
	{
		return 0;				
	}
	
	this.CalculateSubpanelOffset = function( oOffsetParentEl, nParentElWidth, nParentElHeight, nSubElWidth, nSubElHeight, nSubPanOffsetX, nSubPanOffsetY, bVert, bRTL, bOffsetEvent )
	{
		var nX = 0, nY = 0;
		
		var oTopmostEl = self.GetTopmostLayoutEl();
		var oElOffsetXY = oOffsetParentEl;				
		var nDocScrollTop = oTopmostEl.scrollTop;
		var nDocScrollLeft = oTopmostEl.scrollLeft;		
		
		var nFreeRight = oTopmostEl.clientWidth - oElOffsetXY.x + nDocScrollLeft - nSubPanOffsetX ;
		var nFreeLeft = oElOffsetXY.x - nDocScrollLeft - nSubPanOffsetX;
		var nFreeTop = oElOffsetXY.y - nDocScrollTop - nSubPanOffsetY;
		var	nFreeBottom = oTopmostEl.clientHeight - oElOffsetXY.y + nDocScrollTop - nSubPanOffsetY;
		
		var bIsFitInRight = false, bIsFitInLeft = false;
		if( bVert )
		{
			if( nSubElWidth < nFreeRight - nParentElWidth )
			{
				bIsFitInRight = true;
			}
			if( nSubElWidth < nFreeLeft )
			{
				bIsFitInLeft = true;
			}
				
			if( bRTL )
			{
				if( bIsFitInLeft )
				{
					nX = - nSubElWidth - nSubPanOffsetX ;
				}
				else
				{
					if( bIsFitInRight )
					{
						nX = nParentElWidth + nSubPanOffsetX;
					}
					else
					{
						nX = nDocScrollLeft + oTopmostEl.clientWidth - oElOffsetXY.x - nSubElWidth;
					}
				}
			}
			else
			{
				if( bIsFitInRight )
				{
					nX = nParentElWidth + nSubPanOffsetX
				}
				else
				{
					if( bIsFitInLeft )
					{
						nX = - nSubElWidth - nSubPanOffsetX ;
					}
					else
					{
						nX = nDocScrollLeft - oElOffsetXY.x;
					}
				}
			}
			
			if( nSubElHeight < nFreeBottom )
			{
				nY = nSubPanOffsetY ;			
			}
			else
			{
				if( nSubElHeight < nFreeTop + nParentElHeight )
				{
					nY = nParentElHeight- nSubElHeight - nSubPanOffsetY ;
				}
				else
				{
					nY = nDocScrollTop - oElOffsetXY.y ;
				}
			}
		}
		else
		{
			if( nSubElWidth < nFreeRight )
			{
				bIsFitInRight = true;
			}
			if( nSubElWidth < nFreeLeft + nParentElWidth )
			{
				bIsFitInLeft = true;
			}
			
			if( bRTL )
			{
				if( bIsFitInLeft )
				{
					nX = nParentElWidth- nSubElWidth - nSubPanOffsetX ;
				}
				else
				{
					if( bIsFitInRight )
					{
						nX = nSubPanOffsetX;
					}
					else
					{
						nX = nDocScrollLeft + oTopmostEl.clientWidth - oElOffsetXY.x - nSubElWidth;
					}
				}
			}
			else
			{
				if( bIsFitInRight )
				{
					nX = nSubPanOffsetX;
				}
				else
				{
					if( bIsFitInLeft )
					{
						nX = nParentElWidth - nSubElWidth - nSubPanOffsetX ;
					}
					else
					{
						nX = nDocScrollLeft - oElOffsetXY.x ;	
					}
				}
			}
			
			if( nSubElHeight < nFreeBottom - nParentElHeight )
			{
				nY = nParentElHeight + nSubPanOffsetY ;			
			}
			else
			{
				if( nSubElHeight < nFreeTop )
				{
					nY = - nSubElHeight - nSubPanOffsetY ;
				}
				else
				{
					nY = nDocScrollTop - oElOffsetXY.y ;
				}
			}
		}
		return { x: nX, y: nY }; 
	}
	
	this.GetElementExtHeight = function( oEl, bTop )
	{
		return 0;
	}
	
	this.GetElementExtWidth = function( oEl, bLeft )
	{
		return 0;
	}
	
	//return difference of the element properties style.height and element offsetHeight
	this.GetHeightDifference = function( oEl )
	{
		var nRes = self.GetElementExtHeight( oEl, false ) + self.GetElementExtHeight( oEl, true );
		return nRes;
	}
	
	//return difference of the element properties style.height and element offsetHeight
	this.GetWidthDifference = function( oEl )
	{
		var nRes = self.GetElementExtWidth( oEl, false ) + self.GetElementExtWidth( oEl, true );
		return nRes;
	}
	
	//return true, when it is differences  properties style.height and element offsetHeight
	this.GetIsOffsetWidthDeviating = function()
	{
		return ( document.compatMode == "CSS1Compat" );
	}

	this.ClearAlign = function( oEl )
	{
	}	
	
	this.GetIsDocReady = function( fnPred )
	{
		return fnPred ? fnPred() : true;
	}

	this.ImportStyles = function( oTrgWnd )
	{
		var oTrgDoc = oTrgWnd.document;
		var aStyles = document.styleSheets;
		for (var i = 0; i < aStyles.length; ++i)
		{
			var oSS = aStyles[i];
			if (oSS && oSS.cssText)
			{
				var oTrgStl = oTrgDoc.createStyleSheet();
				var oRule = oSS.rules[0];
				if (oRule){ oRule.selectorText ? oTrgStl.cssText = oSS.cssText : oTrgStl.addRule("*", oSS.cssText) }
			}
		}
	}
	
	this.GetIsTargetSelf = function( sTarget )
	{
		var bRes = true;
		if( sTarget )
		{
			bRes = self.TargetSelf == sTarget;
		}
		
		return bRes;
	}
	
	this.NavigateTo = function( sUrl, sTarget )
	{
        var bRes = false;
		if( sUrl )
		{
			if( self.GetIsTargetSelf( sTarget ) )
			{
				bRes = true;
				location.href = sUrl;
			}
			else if( sTarget == self.TargetBlank )
			{
				bRes = true;
				window.open( sUrl, self.TargetBlank );				
			}
			else if( sTarget )
			{
			 	var frmTarget = self.FindFrame( sTarget );
				if( frmTarget )
				{
					bRes = true;
					frmTarget.location.href = sUrl;
				}
			}
		}
		
		return bRes;
	}
	
	this.FindFrame = function( sFrmName, oWnd )
	{
	    var oFindWnd = ( null == oWnd )? window : oWnd;
	    var frmTarget = oFindWnd.frames[sFrmName];
	    if( !frmTarget && oFindWnd.parent && !( oFindWnd === oFindWnd.top ) )
	    {
	        frmTarget = self.FindFrame( sFrmName, oFindWnd.parent );
	    }
	     
	    return  frmTarget;
	}

	// Private
	function PreCreateLoop()
	{
		if (self.GetIsDocReady( m_fnPreCreatePred ))
		{
			m_fnCreate();
		}
		else
		{
			UTIL.PostExec( PreCreateLoop );
		}
	}
	
}

function SF_CSSBase( m_oParams )
{
	// panel states
	var c_nStateNone	= 0;
	var c_nStateHover	= 1;
	var c_nStateDown	= 2;
	var c_nStateExpanded= 3;	

	var c_asItemClsParts = 
	[
		"Default",
		"Hover",
		"Active",
		"Expanded",
		
		"Pushed",
	];

	var c_asClsChildEl = 
	[
		"tdSFStdImgCont",	// cell holding image
		"tdSFStdTextCont",	// cell holding text
		"divSFStdImgCont",	// intermediary <div>-container for image
	];

	var self = this;
	var DOM = m_oParams.DOM;
	
	this.TransitionFilterNone		= -1;
	this.TransitionFilterFade		= -1;
	this.TransitionFilterDissolve	= -1;
	this.TransitionFilterPixelate	= -1;
	this.TransitionFilterWipeDown	= -1;
	this.TransitionFilterWipeLeft	= -1;
	this.TransitionFilterWipeRight	= -1;
	this.TransitionFilterWipeUp		= -1;
	
	this.DisplayNone = 0;
	this.DisplayInline = 1;
	this.DisplayBlock = 2;
	this.DisplayEmpty = 3;
	
	var c_asDisplayValue =
	[
		"none",
		"inline",
		"block",
		"",
	];

	this.SetItemClass = function( oEl, nState, nDefaultState )
	{
		var nDefState = ( null == nDefaultState ) ? c_nStateNone : nDefaultState;
		if (!oEl.ClassBase)
			oEl.ClassBase = oEl.className;
		
		var sClsEx = "";
		if (nDefaultState != nState)
		{
			var sAttr = "Class" + c_asItemClsParts[ nDefState ];
			var sDefClass = DOM.GetAttribute( oEl, sAttr );
			sClsEx = " " + sDefClass + "_" + c_asItemClsParts[ nState ];
		}

		var sCls = oEl.ClassBase + sClsEx;
		if (sCls != oEl.className)
			oEl.className = sCls;
	}

	this.SetLookClass = function( oEl, nState, nDefaultState )
	{
		var nDefState = ( null == nDefaultState ) ? c_nStateNone : nDefaultState;
		var sAttr = "Class" + c_asItemClsParts[ nState ];
		var sCls = DOM.GetAttribute( oEl, sAttr );
		if (!sCls && nDefaultState != nState)
		{
			sAttr = "Class" + c_asItemClsParts[ nDefState ];
			sCls = DOM.GetAttribute( oEl, sAttr );
		}
		if (sCls != oEl.className)
			oEl.className = sCls ? sCls : "";
	}
	
	this.SetImgSrc = function( oImg, nState, sAttrBase )
	{
		var sAttr = sAttrBase + c_asItemClsParts[ nState ];
		var sSrc = DOM.GetAttribute( oImg, sAttr );
		if (!sSrc && c_nStateNone != nState)
		{
			switch (nState)
			{
				case c_nStateDown:
				case c_nStateExpanded:
				{
					this.SetImgSrc( oImg, c_nStateHover, sAttrBase );
					return;
				}
				default:
				{
					this.SetImgSrc( oImg, c_nStateNone, sAttrBase );
					return;
				}
			}
		}

		if (oImg.SrcAttr != sSrc)
		{
			oImg.SrcAttr = (sSrc ? sSrc : "");
			this.SetVisible( oImg, oImg.SrcAttr );
			oImg.src = DOM.EnsureImg( oImg.SrcAttr );
		}
	}
	
	this.SetVisible = function( oEl, bVal )
	{
		var oElStl = oEl.style;
		oElStl.visibility = (bVal) ? "" : "hidden";
	}
	
	this.SetDisplay = function( oEl, nDisplay )
	{
		var oElStl = oEl.style;
		if ( null == nDisplay )
		{
			nDisplay = self.DisplayEmpty;
		}
		oElStl.display = c_asDisplayValue[ nDisplay ];
	}

	this.SetZIndex = function( oEl, nIdx )
	{
		var oElStl = oEl.style;
		oElStl.zIndex = (null != nIdx ? nIdx : "");
	}
	
	this.SetOpacity = function ( oEl, nIdx )
	{
	}
	
	this.SetFocusSetting = function( oEl, oValue )
	{
		return null;
	}
	
	this.GetTransitionFilter = function( nVal )
	{
		return "";
	}	
	
	function GetStateMask( aStates )
	{
		var dwMask = 0;
		for (var i = 0; i < aStates.length; ++i)
		{
			if (aStates[i])
			{
				dwMask |= (1 << i);
			}
		}
		return dwMask;
	}
	
	function GetClassFromStates( aStates )
	{
	}
	
	function GetStatesFromClass( sClass )
	{
		var aStates = [];
		for (var i = 0; i < c_asPanClsParts.length; ++i)
		{
			aStates[i] = ( (sClass.indexOf( c_asPanClsParts[i] ) > 0) ? 1 : 0 );
		}
		return aStates;
	}
}
