﻿// take care of firebug console in IE
if( typeof(console) == 'undefined' ) window.console = {log:function(){}};

/*
	GTP, 9/12/2008:
	Some accordion panels can now be marked with a class name of 'fake'.
	This means that we don't actually want to open up its accordion_content when its accordion_toggle is clicked.
	These exist only to catch click events and call a manually placed .onActivate().
*/

var Accordion = Class.create({
	element: null,
	duration: 0.2,
	
	initialize: function(element, config){
		this.isIE6 = navigator.userAgent.indexOf("MSIE 6.0") != -1;
		this.element = $(element);
		this.element.accordion = this;
		
		this.config = Object.extend({
			solo: true,					// only one panel open at a time?
			fixedHeight: false,			// fixed height?  duh
			disabledByDefault: false,	// disable opening of all panels by default
			oneAlwaysOpen: false		// should one panel always be open?
		}, config || {} );
		
		if( this.config.fixedHeight ){
			this.config.solo = true;
			Event.observe( window, 'resize', this.onResize.bindAsEventListener(this) );
		}
		
		var thePosition = this.element.getStyle('position')
		if( thePosition != 'absolute' && thePosition != 'static' ) this.element.setStyle({ position: 'relative' });
		
		this.getPanels().each(function(p) { this.setupPanel(p); }.bind(this));
	},
	
	
	// internals
	
	setupPanel: function( p ){
		if( !p.hasClassName('accordion_panel') ) return;
		
		p.toggle = p.down('.accordion_toggle');
		p.content =  p.down('.accordion_content');
		p.scroller = p.down('.scroller');
		p.toolbar = p.down('.toolbar');
		
		// configure the style of the content pane
		p.content.setStyle({
			overflow:'hidden',
			padding:0,
			display:'block',
			position:'relative'
		});
		
		if( this.config.fixedHeight && p.toolbar ) {
			p.scroller.setStyle({
				position: 'absolute',
				overflow: 'auto',
				top:p.toolbar.getHeight()+'px', bottom:'0px', left:'0px', right:'0px'
			});
		} else if (this.config.fixedHeight) {
			p.content.setStyle({ overflow:'auto' });
		}
		
		// disable panel, if necessary
		p.disabled = this.config.disabledByDefault;
	
		// extend panel DOM element with nice methods!!
		p.open = function(){ this.openPanel(p); return p; }.bind(this);
		p.close = function(){ this.closePanel(p); return p; }.bind(this);
		p.enable = function(){ this.enablePanel(p); return p; }.bind(this);
		p.disable = function(){ this.disablePanel(p); return p; }.bind(this);
		
		// hide content box, unless it's open by default, and always if this is a fake
		if( !p.hasClassName('open') || p.hasClassName('fake') ){
			p.content.setStyle({ height: '0px' });
			p.content.hide();
		} else if ( p.hasClassName('open') && this.config.fixedHeight ) {
			p.open();
			this.resizeMe();
		}
		
		// bind event listener to toggle
		Event.observe( p.toggle, 'click', this.onToggleClick.bindAsEventListener(this) );
	},
	getPanels: function(){
		var firstAccordion = this.element.down('.accordion_panel');
		if (firstAccordion)
			return $(firstAccordion.parentNode).childElements();
		else
			return [];
	},
	openPanelHeight: function(){
		return this.getPanels().inject(this.element.getHeight(), function( h, panel ){
			return h - panel.toggle.getHeight();
		});
	},
	resizeMe: function() {
		var theOpenPanel = this.getPanels().find(function(e){return e.hasClassName('open')});
		if( theOpenPanel ){
			var theOpenContent = theOpenPanel.down('.accordion_content')
			var newHeight = this.openPanelHeight();
			theOpenContent.setStyle({ height:newHeight+'px' });
		}
	},
	
	
	// event handlers
	
	onToggleClick: function( e ){
		this.togglePanel( e.element().up('.accordion_panel') );
	},
	onResize: function(){ this.resizeMe(); },
	
	
	// actions
	
	togglePanel: function( panel ){
		if( panel.hasClassName('open') && !this.config.oneAlwaysOpen ) this.closePanel( panel );
		else this.openPanel( panel );
	},
	openPanel: function( panel ){
		if( panel.disabled || panel.hasClassName('open') ) return;
		
		if( panel.openCallback ) panel.openCallback();
		
		var newStyle;
		
		if( panel.onActivate ) panel.onActivate( panel );
		panel.addClassName('open');
		
		if( panel.hasClassName('fake') ) {
			panel.siblings().each(function( sibling ){
				this.closePanel( sibling, false );
			}.bind(this));
			return;
		};
		
		panel.content.show();
		if( panel.toolbar ) panel.scroller.setStyle({ top:panel.toolbar.getHeight()+'px' });
		
		if( this.config.fixedHeight )
			newStyle = { height: this.openPanelHeight()+'px' };
		else
			newStyle = { height:panel.content.scrollHeight+'px' };
		
		var fx = [ new Effect.Morph( panel.content, { style:newStyle, sync:true } ) ];
		if( this.config.solo ){
			panel.siblings().each(function( sibling ){
				if( sibling.hasClassName('open') ) fx.push( this.closePanel(sibling, true) );
			}.bind(this));
		}
		new Effect.Parallel( fx, { duration:this.duration, afterFinish:this.afterOpenPanel.bind(this, panel), queue:'front' });
		
	},
	closePanel: function( panel, parallel ){
		if( !panel.hasClassName('open') ) return;
		panel.removeClassName('open');
		
		if( panel.closeCallback ) panel.closeCallback();
		
		var newStyle = { height:'0px' };
		var options = { style:newStyle, duration:this.duration, afterFinish:this.afterClosePanel.bind(this, panel), queue:'front' };
		Object.extend( options, parallel ? {sync:true} : {duration:this.duration} );
		
		panel.content.setStyle({ height: panel.content.getHeight() + 'px' });
		return new Effect.Morph( panel.content, options );
	},
	enablePanel: function( panel ){ panel.disabled = false; },
	disablePanel: function( panel ){ panel.disabled = true; },
	
	
	// callbacks
	
	afterOpenPanel: function( panel ){
		if (this.isIE6) panel.content.setStyle({ width: panel.content.getWidth() + "px"});
		if( !this.config.fixedHeight ) panel.content.setStyle({ height:'auto'}); /* this has to happen after the width is set, or ie6 will crash */
	},
	afterClosePanel: function( panel ){
		panel.content.hide();
	}
});