/*
 Class:
 Accordion (inspired by accordion.js v2.0 from Kevin P Miller | http://www.stickmanlabs.com)
 
 Requirements:
 prototype 1.6.0.3
 scriptaculous >= 1.8.1
 
 tested under
 prototype 1.6.1
 scriptaculous 1.8.3
 
 Copyright (c) 2008 Ralph Senger

 Author: Ralph Senger

 Accordion is freely distributable under the terms of an MIT-style license.

*/


 // overwite existing script.aculo.us effect-class because of bad implementation, sorry
 Effect.Scale.addMethods({
 
 	setDimensions: function(height, width) {
	    var d = { };
	    if (this.options.scaleX) d.width = width.round() + 'px';
	    d.height = this.options.scaleY ? height.round() + 'px' : this.options.scaleMode.originalHeight != undefined ? this.options.scaleMode.originalHeight + 'px' : '';
	    if (this.options.scaleFromCenter) {
	      var topd  = (height - this.dims[0])/2;
	      var leftd = (width  - this.dims[1])/2;
	      if (this.elementPositioning == 'absolute') {
	        if (this.options.scaleY) d.top = this.originalTop-topd + 'px';
	        if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
	      } else {
	        if (this.options.scaleY) d.top = -topd + 'px';
	        if (this.options.scaleX) d.left = -leftd + 'px';
	      }
	    }
	    this.element.setStyle(d);
    }
    
  });

// the class
if(!Accordion) {

	var Accordion = Class.create({
		
		initialize: function(_eContainer, options) {
			
			// the base of all
			this.container = $(_eContainer) || new Element('div');
			
			// remind the heighest height
			this.elementMaxSize = 0;
			
			// here you'll find the active accordion or null
			this.activePanel = null;
			
			// we want only one opening animation at once
			this.openingInProgress = false;
			this.closingInProgress = false;
			
			// default options
			this.options = Object.extend({
				'openOnStart': 'first',
				'alwaysKeepOneOpen': false,
				'onStart': Prototype.emptyFunction,
				'onOpen': Prototype.emptyFunction,
				'afterOpen': Prototype.emptyFunction,
				'onClose': Prototype.emptyFunction,
				'afterClose': Prototype.emptyFunction,
				'onEvent': 'click',
				'classToggle': 'acToggle',
				'classActive': 'acActive',
				'classContent': 'acContent',
				'dynamicSize': true,
				'direction': 'vertical',
				'duration': 0.5
				}, options || {});
			
			// the animating options
			if (this.options.direction == 'vertical')
				this.effectOptions = new Object({ 'scaleX': false, 'scaleY': true, 'duration': this.options.duration });
			else
				this.effectOptions = new Object({ 'scaleX': true, 'scaleY': false, 'duration': this.options.duration });

			this._initPanels();

			// start the accordion
			this.startAccordion();
			},
			
			
			
		_initPanels: function(){
			
			// get all elements of the accordion within container which has
			// classToggle from the options as style class definition
			this._eAccordionToggles = $$('#'.concat(this.container.identify(), ' .', this.options.classToggle));
			this._eAccordionContents = $$('#'.concat(this.container.identify(), ' .', this.options.classContent));
			this._eAccordionActives = $$('#'.concat(this.container.identify(), ' .', this.options.classActive));
			
			// close all content elements and recieve their height for
			// getting the maximum height
			this._eAccordionContents.each(
				function(_eContent){
					this.elementMaxSize = Math.max(this.elementMaxSize, _eContent.getHeight());
					_eContent.hide();
					}.bind(this));
			
			// setting the maximum height to each panel
			if (!this.options.dynamicSize)
				this._eAccordionContents.each(
					function(_eContent){
						_eContent.setStyle({ 'height': ''.concat(this.elementMaxSize, 'px') });
						}.bind(this));
			
			// observe all toggle elements
			this._eAccordionToggles.each(
				function(_eToggle, index){
					
					// save the position in the array
					_eToggle.index = index;
					
					// connecting toggle + content
					_eToggle._eMyContent = this._eAccordionContents[index];
					_eToggle._eMyContent._eMyToggle = _eToggle;
					
					// observe it
					_eToggle.observe(this.options.onEvent, this._observeToggle.bindAsEventListener(this, _eToggle));
					
					// the activating function
					_eToggle.activatePanel = function(){
					
						// normal mode: you can close all panels of the accordion
						if (!this.options.alwaysKeepOneOpen) {
						
							// hide the current active accordion
							if (this.activePanel != null)
								this._closePanel(this.activePanel);
							
							// show the desired panel & keep this one in mind
							if (this.activePanel != _eToggle){
								this._openPanel(_eToggle);
								this.activePanel = _eToggle;
								}
							else
								this.activePanel = null;
							}
						// extended mode: there must be always on open panel
						else{
							var _eClosePanel = null;
							var _eOpenPanel = null;
							
							// get for hiding the current active accordion
							if (this.activePanel != null)
								_eClosePanel = this.activePanel;
							
							// get for showing the desired panel
							if (this.activePanel != _eToggle)
								_eOpenPanel = _eToggle;
							else{
								var prevIndex = _eToggle.index - 1;
								var nextIndex = (_eToggle.index + 1) % this._eAccordionToggles.length;
								
								// getting an alternate panel for opening
								if (nextIndex != _eToggle.index)
									_eOpenPanel = this._eAccordionToggles[nextIndex];
								else if (prevIndex != _eToggle.index)
									_eOpenPanel = this._eAccordionToggles[prevIndex];
								}
							
							// hide and open the correct ones
							if (_eClosePanel && _eClosePanel != _eOpenPanel && this._eAccordionToggles.length > 1)
								this._closePanel(_eClosePanel);
							
							if (_eOpenPanel && _eClosePanel != _eOpenPanel){
								this._openPanel(_eOpenPanel);
								this.activePanel = _eOpenPanel;
								}
							}
						}.bind(this)
					}.bind(this));
			
			// option: should all accordions have the same height?
			if (!this.options.dynamicSize)
				this._eAccordionContents.each(
					function(_eContent){
						_eContent.setStyle({ 'height': ''.concat(this.elementMaxSize, 'px') });
						}.bind(this)
					);
					
			},
			
			
			
		startAccordion: function(){
			
			// call the event "onStart"
			this.options.onStart(this._eAccordionToggles);
			
			var panels = this._getOpenedPanels();
			
			if (panels) {
				if (panels.length > 1) {
					this.options.alwaysKeepOneOpen = 'loose';
					panels.each(function(_ePanel){
						if (_ePanel)
							this._openPanel(_ePanel);
						}.bind(this));
					}
				else if (panels.length == 1)
					panels[0].activatePanel();
				}
			},
			
			
			
		_observeToggle: function(event, _eToggle){
			if (!this.openingInProgress && !this.closingInProgress){
				if(this.options.alwaysKeepOneOpen != 'loose')
					_eToggle.activatePanel();
				else {
					if (_eToggle.opened)
						this._closePanel(_eToggle);
					else
						this._openPanel(_eToggle);
					
					this.activePanel = null;
					}
				}
			},
			
			
			
		_openPanel: function(_ePanel){
			// preventing this accordion for showing double animating which causes layout problems
			this.openingInProgress = true;
			
			// call the event "onOpen"
			this.options.onOpen(_ePanel, _ePanel._eMyContent);
			
			// show this content & reset the flag for the animation
			var effectOptions = Object.extend({ 'afterFinish': function(_ePanel){ _ePanel.addClassName(this.options.classActive); _ePanel.opened = true; this.openingInProgress = false; this.options.afterOpen(_ePanel, _ePanel._eMyContent); }.bind(this, _ePanel) }, this.effectOptions);
			new Effect.BlindDown(_ePanel._eMyContent, effectOptions);
			},
			
			
			
		_closePanel: function(_ePanel){
			// preventing this accordion for showing double animating which causes layout problems
			this.closingInProgress = true;
			
			// call the event "onOpen"
			this.options.onClose(_ePanel, _ePanel._eMyContent);
			
			// hide this content & reset the flag for the animation
			var effectOptions = Object.extend({ 'afterFinish': function(_ePanel){ _ePanel.removeClassName(this.options.classActive); _ePanel.opened = false; this.closingInProgress = false; this.options.afterClose(_ePanel, _ePanel._eMyContent); }.bind(this, _ePanel) }, this.effectOptions);
			new Effect.BlindUp(_ePanel._eMyContent, effectOptions);
			},
			
			
			
		_getOpenedPanels: function(){
			var elemente = new Array();
			
			if (this._eAccordionToggles && this._eAccordionContents) {
				// which accordion should be displayed
				switch (this.options.openOnStart){
					case 'first':
						elemente = new Array(this._eAccordionToggles.first());
						break;
					
					case 'last':
						elemente = new Array(this._eAccordionToggles.last());
						break;
					
					case 'all':
						elemente = this._eAccordionToggles;
						break;
					
					default:
						if (Object.isArray(this.options.openOnStart))
							elemente = this.options.openOnStart.collect(function(item){
								if (Object.isNumber(item))
									return this._eAccordionToggles[item];
								
								else if (Object.isElement(item))
									return item;
								}.bind(this));
							
						else
							if(this.options.openOnStart || (this.options.alwaysKeepOneOpen && this.options.alwaysKeepOneOpen != 'loose'))
								elemente = new Array(this._eAccordionToggles[parseInt(this.options.openOnStart) ? parseInt(this.options.openOnStart) : 0]);
					}
				
				if (this._eAccordionActives.length > 0)
					elemente = elemente.concat(this._eAccordionActives);
				}
			
			return elemente;
			},
			
			
			
		getElement: function(){
			return this.container;
			}
		});
	}
