/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * File:		css_effects.js
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *
 * Purpose:	Automatically apply special effects to matching CSS classes,
 *			
 * Copyright:	Synaptic Mash 2008 All Rights Reserved
 *
 * Classes:
 *		*
 *		
 * Requirements:
 *		scriptaculous_effects
 *
 * Developer contact:	Jason Hillier <jason.hillier@synapticmash.com>
 * 
 * Notes:
 * ------
 *	DOMLoad, AJAX special FX. 
 *	
 *	FXGrayout
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

function NeedsProcessing( el )
{
	if ( el.processed ) return false;
	el.processed = true;
	return true;
}
 
var CSSEffects =
{
	Init: function()
	{
		if ( $$('html.oRTL').length == 0 && $$('html.oLTR').length == 0 ) {
			$$('html')[0].addClassName('oLTR');
		}
		if ( $$('.ReportLayout').length != 0 ) {
			$$('html')[0].addClassName('ReportLayout');
		}
		CSSEffects.FXAutoShrink.Init();
		CSSEffects.FXAutoExpand.Init();
		CSSEffects.FXEllipsis.Init();
		CSSEffects.FXGrayout.Init();
		CSSEffects.FXTab.Init();
		CSSEffects.FXInputDirector.Init();
		CSSEffects.FXImageClip.Init();
		CSSEffects.FXImageScale.Init();
		CSSEffects.FXShowGrid.Init();
		CSSEffects.FXEqualHeight.Init();
		CSSEffects.FXHover.Init();
		CSSEffects.FXFixed.Init();
		CSSEffects.FXVerticalNavigation.Init();
	},
	
	FXImageClip:
	{
		Init: function()
		{
			$$(".FXImageClip").each(function(el){
				var clip = el.readAttribute('clip').split(',');
				var maxwidth = el.up().getWidth();//readAttribute('maxwidth');
				var ratio = maxwidth / clip[2];
				if ( ratio > 1 ) ratio = 1;
				el.setStyle({
					display:'block',
					overflow:'hidden',
					width:(clip[2]*ratio)+'px',
					height:(clip[3]*ratio)+'px'
				});
				var img = el.down('img');
				img.setStyle({
					left:'-'+(clip[0]*ratio)+'px',
					top:'-'+(clip[1]*ratio)+'px',
					position:'relative'
				});
				CSSEffects.FXImageClip.Test( ratio, img );
				img.onload = function(){
					CSSEffects.FXImageClip.Test( ratio, img );
				};
				
			});
		},
		Test: function( ratio, img )
		{
			if ( !img.readAttribute('proc') && img.getWidth() > 0 ) {
				img.writeAttribute('proc',true);
				img.setStyle({
					width:( img.getWidth() * ratio ) + 'px',
					height:( img.getHeight() * ratio ) + 'px'
				});
			}
		}
	},
	
	FXImageScale:
	{
		Init: function()
		{
			$$(".FXImageScale").each(function(grp){
				var maxwidth = grp.readAttribute('maxwidth');
				if (maxwidth <= 1)
					maxwidth = 250;
				grp.select('img').each(function(img){
					CSSEffects.FXImageScale.Test( maxwidth, img );
				});
			});
		},
		Test: function( maxwidth, img ) {
			if ( img.getWidth() == 0 ) {
				var _img = img;
				setTimeout(function(){
					CSSEffects.FXImageScale.Test( maxwidth, _img );
				},10);
			} else if ( img.getWidth() > maxwidth ) {
				var ratio = img.getHeight() / img.getWidth();
				img.setStyle({
					width:( maxwidth ) + 'px',
					height:( maxwidth * ratio ) + 'px'
				});
			}
		}
	},
	
	FXEllipsis:
	{
		Init: function()
		{
			$$(".FXEllipsis").each(function(item) {
				if ( !item.hasClassName('processed') ) {
					var top = item;
					top.addClassName('processed');
				
					//*
					var width = item.up().getWidth() - ( parseFloat( item.up().getStyle('padding-left') ) + parseFloat( item.up().getStyle('padding-right') ) );
					item.setStyle({ width:width+'px' });
					var container = item;
					
					var content = item.innerHTML;
					item.innerHTML = "<span>" + content + "</span>";
					item = item.down();
					
					if ( item.getWidth() > width ) {
						if ( top.hasAttribute( "title" ) ) {
							item.writeAttribute( "title", top.readAttribute( "title" ) + " - " + content );
						} else {
							item.writeAttribute( "title", content );
						}
					
						var left = 0;
						var right = content.length;
						var lastCursor = -1;
						var cursor = Math.floor( left + ( (right-left) / 2 ) );
						while( lastCursor != cursor ) {
							lastCursor = cursor;
						
							item.innerHTML = content.substring( 0, cursor ) + "...";
							
							if ( item.getWidth() < width ) {
								left = cursor;
							} else {
								right = cursor;
							}
							
							cursor = Math.floor( left + ( (right-left) / 2 ) );
						}
					} else {
						container.setStyle({ width:item.getWidth() + 'px' });
					}
				}
			});
		}
	},
	
	FXGrayout:
	{
		Init: function()
		{
			$$(".FXGrayout").each(function(item)
				{
					if (item.FXGrayout == null)
					{
						var tmpOverlay = document.createElement("DIV");
						item.setStyle({position:'relative'});
						
						item.appendChild(tmpOverlay);
						tmpOverlay = $(tmpOverlay);
						
						tmpOverlay.setStyle({position:'absolute', backgroundColor:'#000000',zIndex:1,cursor:'not-allowed'});
						tmpOverlay.style.top=0;
						tmpOverlay.style.left=0;
						
						if (isIE6)
						{
							tmpOverlay.style.width= item.getWidth() + "px";
							tmpOverlay.style.height= item.getHeight() + "px";
							
							//bad hack fix
							if (item.getStyle('padding-left') != null)
								tmpOverlay.style.left = '-' + item.getStyle('padding-left');
						}
						else
						{
							tmpOverlay.style.width= "100%";
							tmpOverlay.style.height= "100%";
						}
						
						tmpOverlay.style.opacity=0.2;
						tmpOverlay.style.filter="alpha(opacity=20.0)";
						
						Object.extend(item, { FXGrayout: true });
					}
				});
		}
	},
	
	FXAutoShrink:
	{
		Init: function()
		{
			
			$$(".FXAutoShrink").each(function(item)
				{
					var tot_width = 0;
					
					item.immediateDescendants().each(function(subelement)
						{
							tot_width += subelement.getWidth();
						});
					
					item.setStyle({width: tot_width + 'px'});
				});
		}
	},
	
	FXAutoExpand:
	{
		Init: function()
		{
			
			$$(".FXAutoExpand").each(function(item)
				{
					if (item.HasExpanded == null)
					{
						new Effect.SlideDownIn(item, {duration: 1.0 });
						Object.extend(item, { HasExpanded: true });
					}
				});
		}
	},
	
	FXInputDirector:
	{
		_InputGroups: [],
		_CurrentGroup: null,
		_CurrentTarget: null,
		_HasInitialized: false,
		
		ReInit: function()
		{
			CSSEffects.FXInputDirector._ScanGroups();
		},
		
		Init: function()
		{	
			if (CSSEffects.FXInputDirector._HasInitialized)
			{	
				// check for new items
				$$(".FXInputDirector").each(function(item)
					{
						var isScanned = item.getAttribute('scanned');
						if(isScanned != "true")
						{
							CSSEffects.FXInputDirector.ReInit();
							return;
						}
					});			
				return; 
			}
			
			CSSEffects.FXInputDirector._ScanGroups();
			
			if (CSSEffects.FXInputDirector._InputGroups.length > 0)
			{
				//arrow key bindings
				document.observe("keydown", CSSEffects.FXInputDirector.OnArrowKey.bindAsEventListener(this));
				CSSEffects.FXInputDirector._HasInitialized = true;
			}
		},
		
		_ScanGroups: function()
		{
			CSSEffects.FXInputDirector._InputGroups = new Array();
			
			$$(".FXInputDirector").each(function(item)
				{
					var txtProperties = item.getAttribute('rel');
					if (txtProperties != null && txtProperties != '')
					{
						txtProperties = txtProperties.evalJSON();
						var group = {Element: item, Properties: txtProperties};
						
						CSSEffects.FXInputDirector._InputGroups.push(group);
						
						if (group.Properties.ManualInputFocus || group.Properties.PMInputFocus)
						{
							CSSEffects.FXInputDirector._CompileGroupTargets(group);
						}
					}
					item.setAttribute('scanned', "true");					
				});
			
			SMLayoutManager.Log.Trace("[FXInputDirector] Scanned " + CSSEffects.FXInputDirector._InputGroups.length + " groups.");
		},
		
		///<Summary>
		///	Public function to update current input target. Only being used by SMPillBox right now.
		///</Summary>
		SetCurrentTarget: function(element)
		{
			if (this._CurrentTarget == element)
				return;
			
			if (document.activeElement != null)
				document.activeElement.blur();
			
			//find which group target belongs to
			this._CurrentTarget = element;
			
			for(var i=0; i<this._InputGroups.length; i++)
			{
				this._CurrentGroup = this._InputGroups[i];
				
				var groupTargetIndex = this._GetGroupTargetIndex();
				if (groupTargetIndex >= 0)
					return;
			}
			
			//didn't find it in the list. clear everything
			this._CurrentGroup = null;
			this._CurrentTarget = null;
		},
		
		OnArrowKey: function(e)
		{
			if (!this._IsArrowKey(e.keyCode))
				return;
			
			if (this._CurrentGroup == null)
				this._CurrentGroup = this._InputGroups[0];
			
			var groupTargetIndex = this._GetGroupTargetIndex();
			
			if (groupTargetIndex == -1)
			{
				this._SetGroupTargetByIndex(0);
			}
			else
			{
				if (this._CurrentGroup.Properties.Direction == this.Directions.UP_DOWN)
				{
					if (e.keyCode == this.ArrowKeys.DOWN)
					{
						groupTargetIndex++;
						this._SetGroupTargetByIndex(groupTargetIndex);
					}
					else if (e.keyCode == this.ArrowKeys.UP)
					{
						groupTargetIndex--;
						this._SetGroupTargetByIndex(groupTargetIndex);
					}
					else if (e.keyCode == this.ArrowKeys.LEFT)
					{
						this._MoveToPrevGroup(groupTargetIndex);
					}
					else if (e.keyCode == this.ArrowKeys.RIGHT)
					{
						this._MoveToNextGroup(groupTargetIndex);
					}
				}
				if (this._CurrentGroup.Properties.Direction == this.Directions.LEFT_RIGHT)
				{
					if (e.keyCode == this.ArrowKeys.RIGHT)
					{
						groupTargetIndex++;
						this._SetGroupTargetByIndex(groupTargetIndex);
					}
					else if (e.keyCode == this.ArrowKeys.TAB && !e.shiftKey)
					{
						groupTargetIndex++;
						if(this._CurrentGroup.Element.InputTargets.length > groupTargetIndex)
						{
							this._SetGroupTargetByIndex(groupTargetIndex);
						}
						else
						{
							this._MoveToNextGroup(groupTargetIndex);
							this._SetGroupTargetByIndex(0);
						}						
					}
					else if (e.keyCode == this.ArrowKeys.LEFT)
					{
						groupTargetIndex--;
						this._SetGroupTargetByIndex(groupTargetIndex);
					}
					else if(e.keyCode == this.ArrowKeys.TAB && e.shiftKey)
					{
						if(groupTargetIndex == 0)
						{
							this._MoveToPrevGroup(groupTargetIndex);
							this._SetGroupTargetByIndex(this._CurrentGroup.Element.InputTargets.length - 1);
						}
						else
						{
							groupTargetIndex--;
							this._SetGroupTargetByIndex(groupTargetIndex);
						}
					}
					else if (e.keyCode == this.ArrowKeys.UP || (e.keyCode == this.ArrowKeys.RETURN && e.shiftKey))
					{
						this._MoveToPrevGroup(groupTargetIndex);
					}
					else if (e.keyCode == this.ArrowKeys.DOWN || (e.keyCode == this.ArrowKeys.RETURN && !e.shiftKey))
					{
						this._MoveToNextGroup(groupTargetIndex);
					}
				}
				else
				{
					SMLayoutManager.Log.Error("[FXInputDirector] Direction not implemented!");
					return;
				}
			}
			
			Event.stop(e);
		},
		
		_MoveToNextGroup: function(target_index)
		{
			for(var i=0; i<this._InputGroups.length; i++)
			{
				if (this._CurrentGroup == this._InputGroups[i])
				{
					if (i < this._InputGroups.length - 1)
					{
						this._CurrentGroup = this._InputGroups[i+1]
						break;
					}
				}
			}
			
			this._SetGroupTargetByIndex(target_index);
		},
		
		_MoveToPrevGroup: function(target_index)
		{
			for(var i=0; i<this._InputGroups.length; i++)
			{
				if (this._CurrentGroup == this._InputGroups[i])
				{
					if (i > 0)
					{
						this._CurrentGroup = this._InputGroups[i-1]
						break;
					}
				}
			}
			
			this._SetGroupTargetByIndex(target_index);
		},
		
		_IsArrowKey: function(keyCode)
		{
			for(var v in this.ArrowKeys)
			{
				if (this.ArrowKeys[v]==keyCode)
					return true;
			}
			
			return false;
		},
		
		_SetGroupTargetByIndex: function(index)
		{
			if (this._CurrentGroup.Element.InputTargets == null)
				this._CompileGroupTargets(this._CurrentGroup);
			if (index >= this._CurrentGroup.Element.InputTargets.length)
				index = this._CurrentGroup.Element.InputTargets.length - 1;
			if (index < 0)
				index = 0;
			this._SetGroupTarget(this._CurrentGroup.Element.InputTargets[index]);
		},
		
		_SetGroupTarget: function(target)
		{
			this._CurrentTarget = target;
			
			if (this._CurrentGroup.Properties.PMInputFocus)
			{
				var control = PM.GetControl(this._CurrentTarget.id);
				control._UI.Focus();
			}
			else if (this._CurrentGroup.Properties.ManualInputFocus)
			{
				this._CurrentTarget.select();
			}
			else
			{
				this._CurrentTarget.ISetInputHook();
			}
			
			if (this._CurrentGroup.Properties.ScrollParent != null)
			{
				//find scrolling parent (a div, or the window itself)
				var scrollable_selector = this._CurrentGroup.Properties.ScrollParent;
				var scroll_parent = null;
				if (scrollable_selector != null)
				{
					scroll_parent = this._CurrentGroup.Element.up(scrollable_selector);
				}
				
				SMLayoutManager.ScrollIntoView(this._CurrentTarget, scroll_parent);
			}
			else
			{
				//otherwise, no scrolling
			}
		},
		
		_GetGroupTargetIndex: function()
		{
			if (this._CurrentGroup == null)
				return -1;
			if (this._CurrentGroup.Element.InputTargets == null)
				this._CompileGroupTargets(this._CurrentGroup);
			
			if (this._CurrentGroup.Element.InputTargets.length == 0)
			{
				//this group is worthless.. remove and retry
				this.RemoveCurrentGroup();
				
				return this._GetGroupTargetIndex();
			}
			
			for(var i=0; i<this._CurrentGroup.Element.InputTargets.length; i++)
			{
				if (this._CurrentGroup.Element.InputTargets[i] == this._CurrentTarget)
					return i;
			}
			
			return -1;
		},
		
		RemoveCurrentGroup: function()
		{
			for(var i=0; i<this._InputGroups.length; i++)
			{
				if (this._InputGroups[i] == this._CurrentGroup)
				{
					this._InputGroups.splice(i, 1);
					
					this._CurrentGroup = this._InputGroups[i];
					return;
				}
			}
		},
		
		_CompileGroupTargets: function(group)
		{
			Object.extend(group.Element, { InputTargets : new Array() });
			
			if (group.Properties.ManualInputFocus || group.Properties.PMInputFocus)
			{
				group.Element.descendants().each(function(item)
					{
						if ((group.Properties.PMInputFocus && item.hasClassName("PMUserControl")) || (group.Properties.ManualInputFocus && item.tagName == "INPUT"))
						{
							SMLayoutManager.Log.Debug("add_targ: " + group.Properties.PMInputFocus);
							SMLayoutManager.Log.Debug("add_targ: %o", item);
							$(item).observe('focus', CSSEffects.FXInputDirector._OnFocusSetTarget.bindAsEventListener(this, group));
							group.Element.InputTargets.push(item);
						}
					});
			}
			else
			{
				group.Element.descendants().each(function(item)
					{
						if (item.ISetInputHook != null)
						{
							group.Element.InputTargets.push(item);
						}
					});
			}
			
			return group.Element.InputTargets.length;
		},
		
		_OnFocusSetTarget: function(e, group)
		{
			CSSEffects.FXInputDirector._CurrentGroup = group;
			CSSEffects.FXInputDirector._CurrentTarget = e.target;
		},
		
		Directions: { UP_DOWN: 1, LEFT_RIGHT: 2 },
		ArrowKeys: { LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40, TAB: 9, RETURN: 13 }
		
	},
	
	FXTab:
	{
		_UniqueGroupCounter: 0,
		_TabGroups: [],
		_OnInitTabQueue: [],
		_ActiveRefreshMappingIDs: [],
		_ToggleState: [],
		
		Init: function()
		{
			CSSEffects.FXTab._OnInitTabQueue = new Array();
			
			$$(".FXTabButton").each(function(item)
				{
					if (item.FXTabButton == null)
					{
						var tmpInstructionsJSON = item.getAttribute('rel');
						if (tmpInstructionsJSON != null)
							tmpInstructionsJSON = tmpInstructionsJSON.evalJSON();
						
						tmpInstructions = Object.extend(
							{
								group: CSSEffects.FXTab._UniqueGroupCounter++,
								ShowOnInit: false,
								ActiveText: null,
								InactiveText: null,
								refresh_mapping_id: null,
								show: [],
								DisableSubLinks: false
							},
							tmpInstructionsJSON);
						
						Object.extend(item, {ins: tmpInstructions});
						
						Object.extend(item,
							{
								TabClick: CSSEffects.FXTab.OnTabClick.bindAsEventListener(this, tmpInstructions, item)
							});
						
						Event.observe(item, 'click', item.TabClick);
						
						if (tmpInstructions.ShowOnInit)
						{
							CSSEffects.FXTab._OnInitTabQueue.push({e: null, ins: tmpInstructions, item: item});
						}

						if (tmpInstructions.IsOpen !== undefined )
						{
							var open = CSSEffects.FXTab._ToggleState[ tmpInstructions.show[0] ];
							if ( open === undefined )
							{
								open = tmpInstructions.IsOpen;
								CSSEffects.FXTab._ToggleState[ tmpInstructions.show[0] ] = open;
							}

							if ( open )
							{
								CSSEffects.FXTab._ToggleState[ tmpInstructions.show[0] ] = false;
								CSSEffects.FXTab._OnInitTabQueue.push({e: null, ins: tmpInstructions, item: item});
							}
							else
							{
								for( var i=0; i<tmpInstructions.show.length; ++i )
									$$(tmpInstructions.show[i]).each(function(el){
										el.setStyle({display:'none'});
									});
							}
						}

						Object.extend(item, { FXTabButton: true });
					}
				});
			
			$$(".FXTabDisplay").each(function(item)
				{
					if (item.FXTabDisplay == null)
					{
						var tmpInstructionsJSON = item.getAttribute('rel');
						if (tmpInstructionsJSON != null)
							tmpInstructionsJSON = tmpInstructionsJSON.evalJSON();
							
						tmpInstructions = Object.extend(
							{
								group: CSSEffects.FXTab._UniqueGroupCounter++
							},
							tmpInstructionsJSON);
						
						var group = CSSEffects.FXTab._FindOrAddGroup(tmpInstructions.group);
						
						group.TabDisplays.push(item);
						
						Object.extend(item, { FXTabDisplay: true });
					}
				});
			
			//go through refresh mappings, keeping track of which groups were refreshed
			var groups = new Array();
			
			for(var i=0; i<CSSEffects.FXTab._ActiveRefreshMappingIDs.length; i++)
			{
				var tabButton = CSSEffects.FXTab.FindByRefreshMappingID(CSSEffects.FXTab._ActiveRefreshMappingIDs[i].refresh_mapping_id);
				
				if (tabButton != null)
				{
					CSSEffects.FXTab.OnTabClick(null, tabButton.ins, tabButton);
					
					groups.push({hash: CSSEffects.FXTab._ActiveRefreshMappingIDs[i].group});
				}
			}
			
			Array.MakeHashTable(groups);
			
			//go through ShowOnInit queue
			for(var i=0; i<CSSEffects.FXTab._OnInitTabQueue.length; i++)
			{
				var cTabButton = CSSEffects.FXTab._OnInitTabQueue[i];
				
				if (groups[cTabButton.ins.group] == null)
				{
					CSSEffects.FXTab.OnTabClick(cTabButton.e, cTabButton.ins, cTabButton.item);
				}
				else
				{
					//already init'd
				}
			}
			
		},
		
		FindByRefreshMappingID: function(refresh_mapping_id)
		{
			var foundItem = null;
			
			$$(".FXTabButton").each(function(item)
				{
					if (item.ins.refresh_mapping_id == refresh_mapping_id)
					{
						foundItem = item;
					}
				});
			
			return foundItem;
		},
		
		CloseTab: function(tabButtonId)
		{
			CSSEffects.FXTab.ClickTab(tabButtonId, true);
		},
		
		OpenTab: function(tabButtonId)
		{
			CSSEffects.FXTab.ClickTab(tabButtonId, false);
		},
		
		ClickTab: function(tabButtonId, setClosed)
		{
			Object.extend($(tabButtonId), { override_ins: { SetClosed: setClosed }});
			
			$(tabButtonId).TabClick();
		},
		
		//instructions = JSON object with effect instructions
		OnTabClick: function(e, ins, button)
		{
			var override_ins;

			if ( ins.IsOpen !== undefined )
			{
				CSSEffects.FXTab._ToggleState[ ins.show[0] ] = !CSSEffects.FXTab._ToggleState[ ins.show[0] ];
			}
			
			if (button.override_ins != null)
			{
				override_ins = button.override_ins;
				button.override_ins = null;
			}
			
			if (ins.DisableSubLinks)
			{
				if (e != null && e.target.tagName == "A")
					return;
			}
			
			var tabGroup = CSSEffects.FXTab._FindOrAddGroup(ins.group);
			
			for (var i=0; i<tabGroup.TabDisplays.length; i++)
			{
				CSSEffects.FXTab.HideElement(tabGroup.TabDisplays[i]);
			}
			
			for (var i=0; i<tabGroup.VisibleItems.length; i++)
			{
				CSSEffects.FXTab.HideElementByCss(tabGroup.VisibleItems[i]);
			}
			
			for (var i=CSSEffects.FXTab._ActiveRefreshMappingIDs.length; i>0; i--)
			{
				if (CSSEffects.FXTab._ActiveRefreshMappingIDs[i-1].group == ins.group)
				{
					CSSEffects.FXTab._ActiveRefreshMappingIDs.splice(i-1, 1);
				}
			}
			
			var toggleOff = false; //flag which indicates user clicked button again
			
			for (var i=0; i<tabGroup.ActiveButtons.length; i++)
			{
				if (button == tabGroup.ActiveButtons[i])
					toggleOff = true;
				
				tabGroup.ActiveButtons[i].removeClassName('FXTabButton_Active');
				
				if (ins.InactiveText != null)
				{
					tabGroup.ActiveButtons[i].innerHTML = ins.InactiveText;
				}
			}
			
			tabGroup.ActiveButtons.clear();
			tabGroup.VisibleItems.clear();
			
			if (override_ins != null)
			{
				if (override_ins.SetClosed)
				{
					//override - forcefully set it to closed
					toggleOff = true;
				}
				else
				{
					toggleOff = false;
				}
			}
			
			if (!toggleOff)
			{
				for(var i=0; i<ins.show.length; i++)
				{
					CSSEffects.FXTab.ShowElementByCss(ins.show[i]);
					tabGroup.VisibleItems.push(ins.show[i]);
				}
				
				if (ins.refresh_mapping_id != null)
				{
					CSSEffects.FXTab._ActiveRefreshMappingIDs.push({group: ins.group, refresh_mapping_id: ins.refresh_mapping_id});
					
					//SMLayoutManager.Log.Debug(CSSEffects.FXTab._ActiveRefreshMappingIDs);
				}
				
				button.addClassName('FXTabButton_Active');
				if (ins.ActiveText != null)
				{
					button.innerHTML = ins.ActiveText;
				}
				tabGroup.ActiveButtons.push(button);
			}
		},
		
		_FindOrAddGroup: function(GroupID)
		{
			for(var i=0; i<CSSEffects.FXTab._TabGroups.length; i++)
			{
				if (CSSEffects.FXTab._TabGroups[i].GroupID == GroupID)
					return CSSEffects.FXTab._TabGroups[i];
			}
			
			var newGroup = { GroupID: GroupID, VisibleItems: [], TabDisplays: [], ActiveButtons: [] }
			
			CSSEffects.FXTab._TabGroups.push(newGroup);
			
			return CSSEffects.FXTab._TabGroups[CSSEffects.FXTab._TabGroups.length - 1];
		},
		
		ShowElementByCss: function(selector)
		{
			var elements = $$(selector);
			
			if (elements.length > 0)
			{
				CSSEffects.FXTab.ShowElement(elements[0]);
			}
			else
			{
				SMLayoutManager.Log.Error("[FXTab] Could not find element to show by css selector: '" + selector + "'");
			}
		},
		
		ShowElement: function(element)
		{
			if (Effect != null && Effect.SlideDownIn != null && 1==0)
			{
				//if we have scriptaculous effects lib
				new Effect.SlideDownIn(element, {duration: 1.0 });
			}
			else
			{
				element.setStyle({display:'block'});
			}
		},
		
		HideElementByCss: function(selector)
		{
			var elements = $$(selector);
			
			if (elements.length > 0)
			{
				CSSEffects.FXTab.HideElement(elements[0]);
			}
			else
			{
				SMLayoutManager.Log.Error("[FXTab] Could not find element to hide by css selector: '" + selector + "'");
			}
		},
		
		HideElement: function(element)
		{
			if (Effect != null && Effect.SlideUpOut != null && 1==0)
			{
				//if we have scriptaculous effects lib
				new Effect.SlideUpOut(element, {duration: 1.0 });
			}
			else
			{
				element.setStyle({display:'none'});
			}
		}
	},
	
	FXShowGrid:
	{
		Init: function()
		{
			if ( $$('.oShowGrid').length ) {
				$$('.oGrid1,.oGrid2,.oGrid3,.oGrid4,.oGrid5,.oGrid6,.oGrid7,.oGrid8,.oGrid9,.oGrid10,.oGrid11,.oGrid12,.oGrid13,.oGrid14,.oGrid15,.oGrid16').each(function(el){
					el.insert({top:'<div class="oShowGridBox"></div>'});
				});
			}
		}
	},
	
	FXEqualHeight:
	{
		Init: function()
		{
			$$('.FXEqualHeight').each(function(parent) {
				var maxHeight = 0;
				parent.childElements().each(function(el){
					var height = el.clientHeight;
					if ( height > maxHeight ) maxHeight = height;
				});
				parent.childElements().each(function(el){
					el.setStyle({height:maxHeight+'px'});
				});
			});
			var maxButtonHeight = 0;
			$$('.SMNavBarButtonContent').each(function(el){
				var height = el.getHeight();
				if ( height > maxButtonHeight ) maxButtonHeight = height;
			});
			if ( maxButtonHeight < 25 ) maxButtonHeight = 25;
			$$('.SMNavBarButton').each(function(el){
				el.setStyle({height:maxButtonHeight+'px'});
			});
		}
	},

	FXHover:
	{
		Init: function()
		{
			$$('.FXHover').each(function(el){
				if ( NeedsProcessing(el) )
				{
					el.inTimer = null;
					el.outTimer = null;
					el.observe('mouseover',function(){
						if ( el.inTimer ) clearTimeout( el.inTimer );
						if ( el.outTimer ) clearTimeout( el.outTimer );
						el.inTimer = setTimeout(function(){
							el.addClassName('Hover');
						},100);
					});
					el.observe('mouseout',function(){
						if ( el.inTimer ) clearTimeout( el.inTimer );
						if ( el.outTimer ) clearTimeout( el.outTimer );
						el.outTimer = setTimeout(function(){
							el.removeClassName('Hover');
						},500);
					});
				}
			});
		}
	},
	
	FXFixed:
	{
		Init: function()
		{
			var elements = $$('.FXFixed');
			if ( elements.length > 0 )
			{
				elements.each(function(el)
				{
					if ( el.processed ) return;
					el.processed = true;
					el.select('.FXContainer').each(function(ch)
					{
						ch.setStyle(
						{
							width: ch.getWidth() + 'px'
						});
					});
				});
				Event.observe(window,'scroll',function()
				{
					var el, offset;
					for( var i=0; i < elements.length; ++i )
					{
						el = elements[i];
						offset = el.viewportOffset();
						if ( offset[1] < 0 && el.getHeight() < document.viewport.getHeight() )
						{
							el.addClassName('Enabled');
						}
						else
						{
							el.removeClassName('Enabled');
						}
					}
				});
			}
		}
	},

	FXVerticalNavigation:
	{
		Init: function()
		{
			var inc = 0;
			$$('.FXVerticalNavigation').each(function(el)
			{
				if ( NeedsProcessing(el) )
				{
					//el.addClassName( 'Texture' + inc++ );
					inc %= 7;
				}
			});
		}
	}
	
}

var FXNames = { None:0,Slide:1 };

//Event.observe(window, 'load', CSSEffects.Init, false);
document.observe("dom:loaded", CSSEffects.Init );
document.observe("SMAjax:CallBack", CSSEffects.Init);
document.observe("PMEvents:DispatchComplete", CSSEffects.Init);
