/* =======================================================
4/25/07
This script written by:
	Justin M. Whiting

Dependencies:
	xcore.js
	xevent.js

========================================================= */
	/**
	CONFIG OBJECT - USED FOR PRESENTATION LOGIC CONFIGURATION...
		Object that can take a series of parameters to configure class names, image paths, etc.
		All closed attributes will be what the 
	*/
	function ConfigObject(){
		// collection based...
		this.changeCollectionStyle 		= false; // should we change the panel headings class/image name on open
		this.changePanelHeadingStyle 	= false; // should we change the panel headings class/image name on open
		this.changePanelContentStyle	= false; // should we change the panel contents class/image name on open
		
		this.changeCollectionTopIndicatorPaths_ONMOUSEOVER 		= false; // should we change the panel collections top indicator image paths
		this.changeCollectionTopIndicatorPaths_OPEN 			= false;
		this.changeCollectionBottomIndicatorPaths_ONMOUSEOVER 	= false; // should we change the panel collections bottom indicator image paths
		this.changeCollectionBottomIndicatorPaths_OPEN 			= false; // should we change the panel collections bottom indicator image paths
		
		// make ofSelected Sticky Based on click...for TOC only...
		this.changeSelectedOnClick 					= false;
		
		// top and bottom indicators...
		this.collection_TOP_Indicator 				= false;
		this.collection_BOTTOM_Indicator 			= false;
		this.collection_TOP_Indicator_MOUSEOVER 	= null;
		this.collection_BOTTOM_Indicator_MOUSEOVER 	= null;
		this.collection_TOP_OPEN 					= false;
		this.collection_BOTTOM_OPEN 				= false;
		
		// collection heading...
		this.collection_MOUSEOVER 	= null;
		this.collection_OPEN 		= null;
		
		this.p_heading_MOUSEOVER 	= null;
		this.p_heading_OPEN 		= null;
		
		this.p_content_MOUSEOVER 	= null;
		this.p_content_OPEN 		= null; 
		
		return this;
		}

	ConfigObject.prototype.c_heading_Identifier 			= "ofAccordionHeading";
	ConfigObject.prototype.p_heading_Identifier 			= "ofSlidingHeading";
	ConfigObject.prototype.p_content_Identifier 			= "ofSlidingContent";
	ConfigObject.prototype.attachPanelMouseOverToCollection	= false;
		
	
	/*
		Object to allow for resetting of dynamic attributes for containers around sliding panels.
	*/
	function ResizableContainer(id){
		this.id 			= id;
		this.domNode 		= $(id);
		this.originalHeight = this.domNode.getHeight();
		this.intendedHeight = this.domNode.getHeight();
		this.decrementHeight = function(amount, constant){
			this.changeHeight(amount,ResizableContainer.INCREASE);
			}
		this.incrementHeight = function(amount){
			this.changeHeight(amount,ResizableContainer.DECREASE);
			}
		this.changeHeight = function(amount, constant){
			//alert(amount + ":" + constant);
			if(constant == ResizableContainer.INCREASE){
				this.domNode.style.height = (this.domNode.getHeight() + amount) + "px";
				//alert(this.domNode.style.height);
				} 
			if(constant == ResizableContainer.DECREASE){
				this.domNode.style.height = (this.domNode.getHeight() - amount) + "px";
				}
			}
		this.resetHeight = function(){
			this.domNode.style.height = (this.originalHeight + "px");
			}
		this.setHeight = function(amount){
			this.domNode.style.height = (amount + "px");
			}
		this.setHeightAccordingToLastKnownHeight = function(amount){
			this.domNode.style.height = (this.lastHeight + amount + "px");
			}
		ResizableContainer.DECREASE = 0;
		ResizableContainer.INCREASE = 1;
		return this;
		}
		
		
		
	/*
		Manager for resizable containers - so all references can be gotten. 
	*/
	function ResizableContainerManager(){
		this.containers = new Object();
		this.createResizableContainer = function(id){
			var ref = new ResizableContainer(id);
			this.containers[id] = ref;
			return ref;
			}
		this.getResizableContainer = function(id){
			return this.containers[id];
			}
		return this;
		}
		
		
		
	/**
		
	*/
	function showHidePanelContent(e){
		var panelInstance = PanelManager.getPanelFromEvent(e);
		panelInstance.slidePanel();
		}



	/**
		Function get the panel from the event raised.
	*/
	function getPanel_Event(eventObj){
		// get reference to the header node...
		var targetNode 		= Event.element(eventObj);
		var panel 			= this.getPanelFromDOMNode(targetNode);
		if(panel == null)return;
		var objs 			= {panel: null, panelCollection: null}
		objs.panel 			= panel;
		objs.panelCollection = panel.panelCollection;
		return objs.panel;
		}



	/**
		Function get the panel collection from the event raised.
	*/
	function getPanel_DOM(domNODE){
		var node = $(domNODE);
		if(this.panels[node.id] != null)return this.panels[node.id];
		var ancestors = Element.ancestors(node);
		for( x = 0 ; x < ancestors.length ; x++ ){
			if(this.panels[ancestors[x].id] != null)return this.panels[ancestors[x].id];
			}
		return null;
		return panel;
		}
		
		
	
		
	/*
		Holds all references to all panel collection objects and passes down calls for mouseover/out, open/close to all appropriate objects.
		API users can call actions explicitly from a reference to this object.
		DOM Object name: PanelManager
	*/
	function PanelCollectionManager(){
		//alert(this.);
		this.actingPanel			= null; // deprecated
		this.callBacks				= new Array(); // call back functions that will pass this object as a reference...
		this.addCallBack = function(func){
								this.callBacks[this.callBacks.length] = func();
								}
		this.notify = function(){
								for( c = 0 ; c < this.callBacks.length ; c++ ){
									if(typeof(this.callBacks[ c ]) != "function")continue;
									this.callBacks[ c ](this);
									}
								}
		this.panelCollectionsById 	= new Array();// by id
		this.panelCollectionIter 	= new Array();// by incrementor
		this.panelCollectionByHeaderNode 	= new Array();// by incrementor
		this.panels					= new Array();
		this.panelsIter 			= new Array();
		this.initPanelCollection	= function(id, optionalSettings){
			var newPanelCollection = new PanelCollection(id, optionalSettings);
			newPanelCollection.panelManager = this;
			return newPanelCollection;
			}
		this.getPanel				= function(named){
										return this.panels[named];
										}
		this.openAllPanels			= function(){
										for( b = 0 ; b < this.panelsIter.length ; b++ ){
											this.panelsIter[b].openPanel();
											}
										}
		this.closeAllPanels			= function(){
										for( b = 0 ; b < this.panelsIter.length ; b++ ){
											this.panelsIter[b].closePanel();
											}
										}
		this.getPanelCollection 	= function(id,secondID){
										return this.panelCollectionsById[id];
										}
		this.addPanelCollection 	= function(panelCollection){
										this.panelCollectionsById[ panelCollection.id ] = panelCollection;
										// if panel collection header node available...
										if(panelCollection.containerNode.getElementsByClassName(ConfigObject.prototype.c_heading_Identifier).length > 0) // --> see next line...
										this.panelCollectionByHeaderNode[ panelCollection.containerNode.getElementsByClassName(ConfigObject.prototype.c_heading_Identifier)[0] ] = panelCollection;
										this.panelCollectionIter[ this.panelCollectionIter.length ] = panelCollection;
										}
		// will perform a slide close or slide open based on the current state of the panel
		this.showHidePanel			= showHidePanelContent;
		// will retreive the panel from the dom node that raised the event
		this.getPanelFromEvent		= getPanel_Event;
		// will retreive the panel from the dom node
		this.getPanelFromDOMNode 	= getPanel_DOM;
		this.getContainerNodes		= function(){
										var containers = new Array();
										for( x = 0 ; x < this.panelCollectionIter.length ; X++ ){
											containers[containers.length] = this.panelCollectionIter[x].containerNode;
											}
										return containers;
										}
		// a way to get panels by the containing object...
		this.accordionsByContainer	= new Array();
		this.getAccordionsByContainerCurrentHeight = function(name){
			var newHeight = 0;
			for( i = 0 ; i < this.accordionsByContainer[name].length ; i++ ){
				newHeight += this.accordionsByContainer[name][i].getCurrentOpenHeight();
				}
			//alert(newHeight);
			return newHeight + 10;
			}
		// visual state management...
		this.mouseOver = function(evt){
							var targetNode = Event.element(evt);
							var targetObject = null;
							if( Element.hasClassName(targetNode, ConfigObject.prototype.p_content_Identifier) ){
								// its a header node...
								} else if( Element.hasClassName(targetNode, ConfigObject.prototype.p_heading_Identifier) ) {
									
									// panel header node...
									targetObject = this.getPanelFromDOMNode(targetNode);
									if(targetObject == null || typeof(targetObject) == "undefined")return;
									targetObject.onMouseOver();
									
								} else if( Element.hasClassName(targetNode, ConfigObject.prototype.c_heading_Identifier) ){
									
									// collection header node...
									targetObject = this.panelCollectionByHeaderNode[targetNode];
									if(targetObject == null || typeof(targetObject) == "undefined")return;
									targetObject.onMouseOver();
									
									}
							}
							
		this.mouseOut = function(evt){
							var targetNode = Event.element(evt);
							var targetObject = null;
							if( Element.hasClassName(targetNode, ConfigObject.prototype.p_content_Identifier) ){
								// its a header node...
								} else if( Element.hasClassName(targetNode, ConfigObject.prototype.p_heading_Identifier) ) {
									
									// panel header node...
									targetObject = this.getPanelFromDOMNode(targetNode);
									if(targetObject == null || typeof(targetObject) == "undefined")return;
									targetObject.onMouseOut();
									
								} else if( Element.hasClassName(targetNode, ConfigObject.prototype.c_heading_Identifier) ){
									
									// collection header node...
									targetObject = this.panelCollectionByHeaderNode[targetNode];
									if(targetObject == null || typeof(targetObject) == "undefined")return;
									targetObject.onMouseOut();
									
									}
							}
								
							/* check to see if the collection allows for other visual states...
							if(!panel.panelCollection.settings.changePanelHeadingStyle)return;
							if(panel.panelCollection.isCollectionOpen())return;
							panel.panelCollection.setVisualState(true);
							}
							*/
		
		return this;
		}
		
	// STATIC...
	PanelCollectionManager.prototype.ContainerManager = new ResizableContainerManager();
		
// ===================================== Panel Methods ===========================================

	/**
	Method: Panel
		Only once the panel has a set content area will the event triggers be set. 
		Explicit Mode: uses id systems.
		Implicit Mode: uses classes to create elements.
	*/
	function initializePanelContent(){
		// setting event handlers for object elements...
		Event.observe(this.headerNode, "mouseover", function(evt){
														var elem = Event.element(evt);
														// default...
														var node = PanelManager.getPanelFromDOMNode(elem);
														if(!node.isOpen && node.panelCollection.settings.changeSelectedOnClick)Element.addClassName( elem, "ofSelected" );
														Element.addClassName( elem, node.panelCollection.settings.panelCollection_MOUSEOVER );
														Element.addClassName( node.headerNode, "ofHover" );
														}
														);
		Event.observe(this.headerNode, "mouseout", function(evt){
														var elem = Event.element(evt);
														// default...
														var node = PanelManager.getPanelFromDOMNode(elem);
														if(!node.isOpen && node.panelCollection.settings.changeSelectedOnClick == true)Element.removeClassName( elem, "ofSelected" );
														if(node.isOpen && !node.panelCollection.settings.changeSelectedOnClick == false)Element.removeClassName( elem, "ofSelected" );
														Element.removeClassName( elem, node.panelCollection.settings.panelCollection_MOUSEOVER );
														Element.removeClassName( node.headerNode, "ofHover" );
														}
														);
		Event.observe( this.headerNode, "click", this.panelCollection.panelManager.showHidePanel );
		
		if(this.panelCollection.isExplicit){
			// if explicit rely upon matching id's... replace gheading with content///
			this.contentNode 	= $( this.headerNode.id.replace("_heading","_content") );
			} else {
			// if not explicit - iterate through same level nodes looking for element with proper class name...
			this.contentNode 	= $(this.headerNode.nextSibling);
			while(	this.contentNode && !this.contentNode.hasClassName(this.panelCollection.settings.panelHeading_MOUSEOUT) ){
				this.contentNode = this.contentNode.nextSibling;
				}
			}
		// set initial properties...also do this each time it runs in case it gets changed dynamically...
		this.headerNode.style.top 		= 0 - this.headerNode.offsetHeight + 'px';
		this.contentNode_MaxHeight 		= this.contentNode.scrollHeight;
		this.contentNode.style.display 	= 'none';
		}
		
		
		
	/**
		The key functionality here is to call the method on the object and the internal 
		object structure will keep track of whether to close/open the panel - and close any other open 
		panels (when the panel collection is in exclusive mode).
		Also sets the visual state of the panels if the panel collection objects settings are to do so.
	*/
	function slideContent(direction){
		// first runs in recursion...
		// is opening?
		var resizable 	= (this.panelCollection.hasResizeableContainer != null && this.panelCollection.resizeablePanel != null)? this.ContainerManager.getResizableContainer(this.panelCollection.resizeablePanel.id) : null ;
		var isResize 	= this.panelCollection.hasResizeableContainer;
		
		if( isResize && typeof(direction) == "undefined" && !this.isOpen){
			//debug("opening: " + resizable.intendedHeight + ":" + this.contentNode_MaxHeight);
			resizable.intendedHeight = resizable.intendedHeight + this.contentNode_MaxHeight;
			//debug("opening: " + resizable.intendedHeight + ":" + this.contentNode_MaxHeight);
			}
		// is closing?
		if( isResize && typeof(direction) == "undefined" && this.isOpen){
			//debug("Closing: " + this.panelCollection.resizeablePanel.intendedHeight + ":" + this.contentNode_MaxHeight);
			resizable.intendedHeight = resizable.intendedHeight - this.contentNode_MaxHeight;
			//debug("Closing: " + resizable.intendedHeight + ":" + this.contentNode_MaxHeight);
			}
			
			
		if(!this.isOpen && 
		   this.panelCollection.isExclusive && 
		   this.panelCollection.currentlyOpenPanel != null && 
		   this.panelCollection.currentlyOpenPanel.isOpen && 
		   !this.panelCollection.currentlyOpenPanel.inProcess && 
		   direction > (this.contentNode_MaxHeight/3)){
			//this.panelCollection.currentlyOpenPanel.slidePanel(direction*-1);
			for( j = 0 ; j < this.panelCollection.iterPanels.length ; j++ ){
				if(this.panelCollection.iterPanels[j].isOpen && this.panelCollection.iterPanels[j] != this){
					this.panelCollection.iterPanels[j].slidePanel();
					}
				}
			}
				
		var rerunFunction 			= true;
		var obj 					= this.headerNode;
		var contentObj 				= this.contentNode;
		contentObj.style.display 	= 'block';
		height 						= (obj == null || obj.scrollHeight  == null || typeof(obj.scrollHeight) == "undefined")? 0 : obj.scrollHeight ;
		if(height == 0)height 		= obj.offsetHeight;
		//if(this.contentNode.scrollHeight && this.contentNode.scrollHeight > 0)this.contentNode_MaxHeight = this.contentNode.scrollHeight;
		
		// if closing...
		if(this.isOpen && (direction > 0)){
			this.contentNode_Height -= this.panelCollection.slideSpeed;
			
			// if we have a sizeable container...
			if(isResize){
				resizable.incrementHeight( this.panelCollection.slideSpeed );
				// if amount goes below original height...
				if(resizable.domNode.getHeight() < resizable.originalHeight)resizable.resetHeight();
				}
				
			this.inProcess 						= true;
			//this.panelCollection.lastProcess 	= this;
			contentObj.style.display 	= 'block';
			if(this.contentNode_Height < 30){
				contentObj.style.visibility 	= 'hidden';
				}
			}
			
		if(this.isOpen && (direction <= 0)){
			rerunFunction 				= false;
			this.isOpen 				= false;
			this.inProcess 				= false;
			contentObj.style.height 	= '0px';
			// this.panelCollection.resizeablePanel.setLastHeightToExistingHeight();
			contentObj.style.display 	= 'none';
			
			if(isResize){
				resizable.domNode.style.height = (resizable.intendedHeight + "px");
				//alert("Closed: " + resizable.intendedHeight + ":" + resizable.domNode.getHeight());
				}
				
			Element.removeClassName(obj, "ofSelected");
			this.panelCollection.onClose();
			this.onClose();
			contentObj.style.height = (this.contentNode_Height <= 1)? 1 : this.contentNode_Height + 'px';
			return;
			}
			
		// in opening state...
		if(!this.isOpen && (this.contentNode_Height != this.contentNode_MaxHeight)){
			this.contentNode_Height += this.panelCollection.slideSpeed;
					
			//this.panelCollection.lastProcess = this;
			this.inProcess = true;
			if(this.contentNode_Height > 30){
				contentObj.style.visibility 	= 'visible';
				}
			// Checking greater....
			if(this.contentNode_Height >= this.contentNode_MaxHeight){
			
				if(isResize){
					resizable.domNode.style.height = (resizable.intendedHeight + "px");
					//alert("Opened: " + resizable.intendedHeight + ":" + resizable.domNode.getHeight());
					}
					
				this.contentNode_Height = this.contentNode_MaxHeight;				
				rerunFunction 			= false;
				this.isOpen 			= true;
				
				// CHANGING VISUAL of heading and content if configured to do so !!!!!!!!
				Element.addClassName(obj,"ofSelected");
				this.panelCollection.onOpen();
				
				this.inProcess 			= false;
				// for recursion...
				this.panelCollection.currentlyOpenPanel = this;
				this.onOpen();
				contentObj.style.height = (this.contentNode_Height <= 1)? 1 : this.contentNode_Height + 'px';
				return;
				
				} else {
				
				// if we have a sizeable container...
				if(isResize){
					resizable.decrementHeight( this.panelCollection.slideSpeed );
					}
					
				}
			}
			
		// set height and top here...
		contentObj.style.height = (this.contentNode_Height <= 1)? 1 : this.contentNode_Height + 'px';
		// if this panel is already open...
		var collectionID 	= this.panelCollection.id;
		var panelID 		= this.id;
		var funcString 		= 'PanelManager.getPanelCollection("' + collectionID + '").getPanel("' + panelID + '").slidePanel(' + this.contentNode_Height +')';
		if(rerunFunction)setTimeout( funcString, this.panelCollection.timerSpeed );
		}

	
	/**
		============================ Panel Object ================================================
	*/
	function Panel(head_node, parentCollection){
		this.headerNode 			= $(head_node);
		this.id 					= head_node.id;
		this.contentNode_Height 	= 0;
		this.contentNode_MaxHeight 	= 0;
		this.contentNode			= null;
		this.panelCollection 		= parentCollection;
		this.panelManager 			= parentCollection.panelManager;
		this.slidePanel				= slideContent;
		this.openPanel	= function(){
			if(!this.isOpen)this.slidePanel();
			}
		this.closePanel	= function(){
			if(this.isOpen)this.slidePanel();
			}
		this.initPanel		 		= initializePanelContent;
		this.isOpen 				= false;
		this.inProcess 				= false;
		this.lastProcess 			= null;
		// set erefernce to 
		this.panelCollection.panelManager.panels[ this.panelCollection.isExplicit ? this.headerNode.id : this.headerNode ] = this;
		this.panelCollection.panelManager.panelsIter[ this.panelCollection.panelManager.panelsIter.length ] = this;
		// event listeners for this panel instance...
		this.onOpenListeners 		= new Array();
		this.onCloseListeners 		= new Array();
		this.onOpenStartListeners 	= new Array();
		this.onCloseStartListeners 	= new Array();
		this.onMouseOver = function(){
							if(this.isOpen)return;
							if(this.panelCollection.settings.p_heading_MOUSEOVER != null){
								Element.addClassName(this.headerNode, this.panelCollection.settings.p_heading_MOUSEOVER);
								}
							if(this.panelCollection.settings.attachPanelMouseOverToCollection)this.panelCollection.onMouseOver();
							}
		this.onMouseOut = function(){
							if(this.isOpen)return;
							if(this.panelCollection.settings.p_heading_MOUSEOVER != null){
								Element.removeClassName(this.headerNode, this.panelCollection.settings.p_heading_MOUSEOVER);
								}
							if(this.panelCollection.settings.attachPanelMouseOverToCollection)this.panelCollection.onMouseOut();
							}
		this.onOpen 	= function(){
							if(this.panelCollection.settings.p_heading_OPEN != null){
								Element.addClassName(this.headerNode, this.panelCollection.settings.p_heading_OPEN);
								Element.removeClassName(this.headerNode, this.panelCollection.settings.p_heading_MOUSEOVER);
								}
							this.panelCollection.panelManager.notify(this);
							}
		this.onClose 	= function(){
							if(this.panelCollection.settings.p_heading_OPEN != null){
								Element.removeClassName(this.headerNode, this.panelCollection.settings.p_heading_OPEN);
								Element.removeClassName(this.headerNode, this.panelCollection.settings.p_heading_MOUSEOVER);
								}
							this.panelCollection.panelManager.notify(this);
							}
		if(this.headerNode != null && typeof(this.headerNode) != "undefined"){
			Event.observe(this.headerNode, "mouseout", function(evet){PanelManager.mouseOut(evet);});
			Event.observe(this.headerNode, "mouseover", function(evet){PanelManager.mouseOver(evet);});
			}
		// add to the list of global panels by id...
		this.panelCollection.panelManager.panels[this.id] = this;
		return this;
		}
	
	
	
	// STATIC ==========================================================================
	Panel.prototype.ContainerManager 					= PanelCollectionManager.prototype.ContainerManager;
	
	
	
	
	// ===================================== PanelCollection Methods ===========================================

	/*
	
	*/
	function initializePanelCollection(){
		// quicker then getElementsByClassName...
		var elems 		= $(this.containerNode).getElementsByClassName("ofSlidingHeading");
		var classname 	= null;
		var ind 		= 0;
		for( i = 0 ; i < elems.length ; i++ ){
			classname = elems[i].className;
			if( classname == null || typeof(classname) == "undefined" ) continue;
			ind = classname.indexOf(this.settings.p_heading_Identifier);
			if( ind == -1 )continue;
			// passed tests...
			var newPanel 							= new Panel( elems[i], this ); // setting the dom node as the index for the object...
			newPanel.initPanel();
			this.panels[elems[i]] 					= newPanel; // internal implementation will search for corresponding nodes...
			this.panelsById[elems[i].id] 			= newPanel;
			this.iterPanels[this.iterPanels.length] = newPanel;
			this.numberOfPanels++;
			}
		}
	
	
	
	/**
		================================= Panel collection object ==========================================
	*/
	function PanelCollection(elementID, settingsObject){
		// INITIALIZERS...
		this.id 				= elementID;
		this.containerNode		= $(this.id); 
		// SETTING DEFAULT BEHAVIOR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		if(settingsObject != null && typeof(settingsObject) != "undefined"){
			this.settings = settingsObject;
			} else {
			// base settings...
			var settingsRef = new ConfigObject();
			settingsRef.changeCollectionStyle 								= false;
			// append style on mouse over of collection...
			settingsRef.changeCollectionBottomIndicatorPaths_OPEN 			= false;
			// change paths for images on mouse opver for the collection...
			settingsRef.changeCollectionBottomIndicatorPaths_ONMOUSEOVER 	= false;
			// change style name --> for changing the panel collections style if the user mouses over...
			settingsRef.attachPanelMouseOverToCollection 					= false;
			// change style name --> for appending style besides the ofSelected...
			settingsRef.changePanelHeadingStyle 							= false;
			// change style name --> for appending style name to contecnt div...
			settingsRef.changePanelContentStyle 							= false;
			this.settings = settingsRef;
			}
		
		this.isExclusive 					= true;// is the collection allowed only one panel open at a time...
		// header div inside the container div
		this.headerNode						= this.containerNode.getElementsByClassName( ConfigObject.prototype.c_heading_Identifier )[0];
		this.panelCollectionBottomIndicator = Element.getElementsByClassName(this.containerNode,"ofAccBottom")[0];
		this.panelCollectionTopIndicator 	= Element.getElementsByClassName(this.containerNode,"ofAccTop")[0];

		this.initState 						= (this.containerNode != null && typeof(this.containerNode) != "undefined");
		this.initPanelCollection 			= initializePanelCollection;
		// panel collection bottom indicator...

		// STATE MANAGEMENT VARIABLES...
		this.isCollectionOpen 				= checkPanelCollectionState;

		// CONSTANTS (WHICH CAN BE CHANGED PER INSTANCE...
		this.slideSpeed 		= 20; // default... set to higher number for faster...
		this.timerSpeed 		= 6;

		this.panelManager 		= PanelManager;
		this.panels 			= new Array();// indexed by dom node...
		this.panelsById 		= new Array();// indexed by id...
		this.iterPanels 		= new Array();// indexed by integer...
		this.openPanels			= new Array();// used to hold for all open panels...
		this.numberOfPanels 	= 0;
		
		// CONTAINER WITH RULES TO HELP IN DYNAMIC PROCESSING...
		this.resizeablePanel 	= null;
		this.hasResizeableContainer = false;
		// pass in id...
		this.registerResizeablePanel = function(container){
			this.resizeablePanel = this.ContainerManager.createResizableContainer(container);
			// register panel collections by container Node...
			if(this.panelManager.accordionsByContainer[container] == null){
				this.panelManager.accordionsByContainer[container] = new Array();
				this.panelManager.accordionsByContainer[container][0] = this;
				} else {
				this.panelManager.accordionsByContainer[container][this.panelManager.accordionsByContainer[container].length] = this;
				}
			this.hasResizeableContainer = true;
			}
		// redundant...
		this.currentlyOpenPanel = null; // used basicly for exclusive mode checking...
		this.lastOpenedPanel 	= null;
		
		this.getPanel = function(id){
							return this.panelsById[id];
							}

		//ethd to hide/sow a panel based upon its internal state...
		this.showHidePanel = function(dom_node){	// general method called from the Panel Collection...
			if(!dom_node.childNodes)dom_node = self.document.getElementById(dom_node);
			this.panels[dom_node].slidePanel();
			}

		// general method to open a panel if not open...
		this.slideOpenPanel = function(dom_node){	// general method called from the Panel Collection...
			if(!dom_node.childNodes)dom_node = self.document.getElementById(dom_node);
			if(!this.panels[dom_node].isOpen)this.panels[dom_node].slidePanel();
			}

		// general method to close a panel if not closed...
		this.slideClosedPanel = function(dom_node){	// general method called from the Panel Collection...
			if(!dom_node.childNodes)dom_node = self.document.getElementById(dom_node);
			if(this.panels[dom_node].isOpen)this.panels[dom_node].slidePanel();
			}

		// general method to open a panel if not open...
		this.openPanel = function(dom_node){	// general method called from the Panel Collection...
			if(!dom_node.childNodes)dom_node = self.document.getElementById(dom_node);
			if(this.panels[dom_node].isOpen)Element.show( this.panels[dom_node].contentNode );
			this.onOpen();
			}

		// general method to close a panel if not closed...
		this.closePanel = function(dom_node){	// general method called from the Panel Collection...
			if(!dom_node.childNodes)dom_node = self.document.getElementById(dom_node);
			if(this.panels[dom_node].isOpen)Element.hide( this.panels[dom_node].contentNode );
			this.onClose();
			}

		this.setIndicatorPaths = setCollectionImagePathsOpenClosed;	
		this.setIndicatorPathsForRollOver = setCollectionImagePathsOverOut;	
		/* this.hasCollectionStateIndicators	= true;
		// panel collection state indicators...for collections witrh singular panel instance where the collection now has a state.
		// set path considerations here ALSO include logic HAS_BOTTOM_INDICATOR
		if( this.panelCollectionBottomIndicator != null && typeof(this.panelCollectionBottomIndicator) != "undefined"){
			this.panelBottomIndicatorPathOpen 	= this.panelCollectionBottomIndicator.src;
			this.panelBottomIndicatorPathClosed = this.panelCollectionBottomIndicator.src.replace("_bottom.","_bottom_open.");// SPECIFICATION HERE 
			}
		this.setPanelCollectionState = function(){
			if(this.panelCollectionBottomIndicator == null || typeof(this.panelCollectionBottomIndicator) == "undefined")return;
			this.setVisualState(this.isCollectionOpen());
			}
		*/	
		// OPEN/CLOSE...............................
		// called from the panel objects...
		this.onOpen = function(){
							if(this.panelCollection_Top_Indicator && !this.settings.collection_OPEN != null){
								Element.addClassName(this.panelCollection_Top_Indicator, this.settings.collection_OPEN);
								}
							if(this.panelCollection_Bottom_Indicator && !this.settings.collection_OPEN != null){
								Element.addClassName(this.panelCollection_Bottom_Indicator, this.settings.collection_OPEN);
								}
							this.setIndicatorPaths();
							}

		// called from the panel objects...
		this.onClose = function(){
							if(this.panelCollection_Top_Indicator && !this.settings.collection_OPEN != null){
								Element.removeClassName(this.panelCollection_Top_Indicator, this.settings.collection_OPEN);
								}
							if(this.panelCollection_Bottom_Indicator && !this.settings.collection_Bottom_Indicator_MOUSEOVER != null){
								Element.removeClassName(this.panelCollection_Bottom_Indicator, this.settings.collection_OPEN);
								}
							this.setIndicatorPaths();
							}

		// MOUSEOVER/OUTS............................
		this.onMouseOver = function(){
							if(this.panelCollection_Top_Indicator && !this.settings.collection_Top_Indicator_MOUSEOVER != null){
								Element.addClassName(this.panelCollection_Top_Indicator, this.settings.collection_Top_Indicator_MOUSEOVER);
								}
							if(this.panelCollection_Bottom_Indicator && !this.settings.panelCollection_Bottom_Indicator_MOUSEOVER != null){
								Element.addClassName(this.panelCollection_Bottom_Indicator, this.settings.collection_Bottom_Indicator_MOUSEOVER);
								}
							if(this.headerNode != null && !this.settings.collection_MOUSEOVER != null){
								Element.addClassName(this.headerNode, this.settings.collection_MOUSEOVER);
								}
							this.setIndicatorPathsForRollOver(true);
							}

		this.onMouseOut = function(){
							if(this.panelCollection_Top_Indicator && !this.settings.collection_Top_Indicator_MOUSEOVER != null){
								Element.removeClassName(this.panelCollection_Top_Indicator, this.settings.collection_Top_Indicator_MOUSEOVER);
								}
							if(this.panelCollection_Bottom_Indicator && !this.settings.collection_Bottom_Indicator_MOUSEOVER != null){
								Element.removeClassName(this.panelCollection_Bottom_Indicator, this.settings.collection_Bottom_Indicator_MOUSEOVER);
								}
							this.setIndicatorPathsForRollOver(false);
							}
		this.getCurrentOpenHeight = function(){
			var height = 0;
			var instance = null;
			for( j = 0 ; j < this.iterPanels.length ; j++ ){
				instance = this.iterPanels[j];
				if(instance.contentNode.style.display == "none")continue;
				height += $(instance.contentNode).getHeight(); //$(instance.headerNode).getHeight() + 
				}
			return height;
			}
		/* set image paths marked for state management...
		this.setVisualStateIndicators 	= setCollStateIndicators;
		// method to set classes and change state image paths (calls above method)...
		this.setVisualState 			= setCollectionVizState;
		*/
		if(this.headerNode != null && typeof(this.headerNode) != "undefined"){
			Event.observe(this.headerNode, "mouseout", function(evet){PanelManager.mouseOut(evet);});
			Event.observe(this.headerNode, "mouseover", function(evet){PanelManager.mouseOver(evet);});
			}
		if(this.panelManager.getPanelCollection(this.id) == null)this.panelManager.addPanelCollection(this);
		// final call just before returning object - to init its internals...
		this.initPanelCollection();
		return this;
		}


	// STATIC ==========================================================================
	PanelCollection.prototype.ContainerManager 		= PanelCollectionManager.prototype.ContainerManager;
	PanelCollection.prototype.isExplicit			= true;
	

	/**
		Method to iterate through the panels to see if any of them are open.
		returns:
			boolean
	*/
	function checkPanelCollectionState(){
		for( i = 0 ; i< this.iterPanels.length ; i++){
			if(this.iterPanels[i].isOpen)return true;
			}
		return false;
		}


	/**
		Method to change all panel collection state indicator image paths to open/closed based on open closed state.
	*/
	function setCollectionImagePathsOpenClosed(){
		
		var isOpen = !this.isCollectionOpen();
		
		if(this.settings.changeCollectionTopIndicatorPaths_OPEN){
			var imageStateIndicators = this.panelCollectionTopIndicator.getElementsByTagName("img");
			for ( y = 0 ; y < imageStateIndicators.length ; y++ ){
				if(isOpen){
					imageStateIndicators[y].src = imageStateIndicators[y].src.replace("_open.","_closed.");
					imageStateIndicators[y].src = imageStateIndicators[y].src.replace("_over.","_closed.");
					} else {
					imageStateIndicators[y].src = imageStateIndicators[y].src.replace("_closed.","_open.");
					imageStateIndicators[y].src = imageStateIndicators[y].src.replace("_over.","_open.");
					}
				}
			}
			
		if(this.settings.changeCollectionBottomIndicatorPaths_OPEN){
			var imageStateIndicators = this.panelCollectionBottomIndicator.getElementsByTagName("img");
			for ( y = 0 ; y < imageStateIndicators.length ; y++ ){
				if(isOpen){
					imageStateIndicators[y].src = imageStateIndicators[y].src.replace("_open.","_closed.");
					imageStateIndicators[y].src = imageStateIndicators[y].src.replace("_over.","_closed.");
					} else {
					imageStateIndicators[y].src = imageStateIndicators[y].src.replace("_closed.","_open.");
					imageStateIndicators[y].src = imageStateIndicators[y].src.replace("_over.","_open.");
					}
				}
			}
			
		}
		
	/**
		Method to change all panel collection state indicator image paths to open/closed based on open closed state.
	*/
	function setCollectionImagePathsOverOut(isOver){
		
		var isOpen = !this.isCollectionOpen();
		
		if(this.settings.changeCollectionTopIndicatorPaths_OPEN){
			var imageStateIndicators = this.panelCollectionTopIndicator.getElementsByTagName("img");
			for ( y = 0 ; y < imageStateIndicators.length ; y++ ){
				if(isOver){
					imageStateIndicators[y].src = imageStateIndicators[y].src.replace("_closed.","_over.");
					imageStateIndicators[y].src = imageStateIndicators[y].src.replace("_open.","_over.");
					}
				if(!isOver){
					imageStateIndicators[y].src = imageStateIndicators[y].src.replace("_over.","_closed.");
					}
				}
			}
			
		if(this.settings.changeCollectionBottomIndicatorPaths_OPEN){
			var imageStateIndicators = this.panelCollectionBottomIndicator.getElementsByTagName("img");
			var src = "";
			for ( y = 0 ; y < imageStateIndicators.length ; y++ ){
				if(isOver){
					imageStateIndicators[y].src = imageStateIndicators[y].src.replace("_closed.","_over.");
					imageStateIndicators[y].src = imageStateIndicators[y].src.replace("_open.","_over.");
					}
				if(!isOver){
					imageStateIndicators[y].src = imageStateIndicators[y].src.replace("_over.","_closed.");
					}
				}
			}
			
		}
		
