//by Valerio Proietti (http://mad4milk.net). MIT-style license.
//accordion.js - depends on prototype.js or prototype.lite.js + moo.fx.js
//version 2.0
/*Class: Fx.Accordion 
90         The Fx.Accordion function creates a group of elements that are toggled when their handles are clicked. When one elements toggles in, the others toggles back. 
91  
92 Arguments: 
93         elements - required, a collection of elements the transitions will be applied to. 
94         togglers - required, a collection of elements, the elements handlers. 
95         options - optional, see options below, and <Fx.Base> options. 
96  
97 Options: 
98         start - either 'open-first' or 'first-open'. 'open-first' will slide that element open, while 'first-open' will just show that element as open immediately with no transition. 
99         fixedHeight - integer, if you want your accordion to have a fixed height. defaults to false. 
100         fixedWidth - integer, if you want your accordion to have a fixed width. defaults to false. 
101         alwaysHide - boolean, if you want the ability to close your only-open item. defaults to false. 
102         wait - boolean. means that open and close transitions can cancel current ones (so if you click 
103          on items before the previous finishes transitioning, the clicked transition will fire canceling the previous). true means that if one element is sliding open or closed, clicking on another will have no effect. for Accordion defaults to false. 
104         onActive - function to execute when an element starts to show 
105         onBackground - function to execute when an element starts to hide 
106         height - boolean, will add a height transition to the accordion if true. defaults to true. 
107         opacity - boolean, will add an opacity transition to the accordion if true. defaults to true. 
108         width - boolean, will add a width transition to the accordion if true. defaults to false, css mastery is required to make this work! 
*/

Fx.Accordion = Class.create();
Fx.Accordion.prototype = Object.extend(new Fx.Base(), {
	
	extendOptions: function(options){
		Object.extend(this.options, Object.extend({
			start: 'open-first',
			fixedHeight: false,
			fixedWidth: false,
			alwaysHide: false,
			wait: false,
			onActive: function(){},
			onBackground: function(){},
			height: true,
			opacity: true,
			width: false
		}, options || {}));
	},

	initialize: function(togglers, elements, options){
		this.now = {};
		this.elements = $A(elements);
		this.togglers = $A(togglers);
		this.setOptions(options);
		this.extendOptions(options);
		this.previousClick = 'nan';
		this.togglers.each(function(tog, i){
			if (tog.onclick) tog.prevClick = tog.onclick;
			else tog.prevClick = function(){};
			$(tog).onclick = function(){
				tog.prevClick();
				this.showThisHideOpen(i);
			}.bind(this);
		}.bind(this));
		this.h = {}; this.w = {}; this.o = {};
		this.elements.each(function(el, i){
			this.now[i+1] = {};
			el.style.height = '0';
			el.style.overflow = 'hidden';
		}.bind(this));
		switch(this.options.start){
			case 'first-open': this.elements[0].style.height = this.elements[0].scrollHeight+'px'; break;
			case 'open-first': this.showThisHideOpen(0); break;
			default: 
					if(this.options.start!=-1){
						
						this.elements[this.options.start].style.height = this.elements[this.options.start].scrollHeight+'px';
						var a = this.togglers[this.options.start].getElementsByClassName(this.options.name+'arrow'+this.options.start)[0];
						if(a!=''){
						a.update("&#9660;");
						}
					}else{
						this.showThisHideOpen(this.options.start);
					}
			break;
		}
	},
	
	setNow: function(){
		for (var i in this.from){
			var iFrom = this.from[i];
			var iTo = this.to[i];
			var iNow = this.now[i] = {};
			for (var p in iFrom) iNow[p] = this.compute(iFrom[p], iTo[p]);
		}
	},

	custom: function(objObjs){
		if (this.timer && this.options.wait) return;
		var from = {};
		var to = {};
		for (var i in objObjs){
			var iProps = objObjs[i];
			var iFrom = from[i] = {};
			var iTo = to[i] = {};
			for (var prop in iProps){
				iFrom[prop] = iProps[prop][0];
				iTo[prop] = iProps[prop][1];
			}
		}
		return this._start(from, to);
	},

	hideThis: function(i){
		if (this.options.height) this.h = {'height': [this.elements[i].offsetHeight, 0]};
		if (this.options.width) this.w = {'width': [this.elements[i].offsetWidth, 0]};
		if (this.options.opacity) this.o = {'opacity': [this.now[i+1]['opacity'] || 1, 0]};
	},

	showThis: function(i){
		if (this.options.height) this.h = {'height': [this.elements[i].offsetHeight, this.options.fixedHeight || this.elements[i].scrollHeight]};
		if (this.options.width) this.w = {'width': [this.elements[i].offsetWidth, this.options.fixedWidth || this.elements[i].scrollWidth]};
		if (this.options.opacity) this.o = {'opacity': [this.now[i+1]['opacity'] || 0, 1]};
	},

	showThisHideOpen: function(iToShow){
		if (iToShow != this.previousClick || this.options.alwaysHide){
			this.previousClick = iToShow;
			var objObjs = {};
			var err = false;
			var madeInactive = false;
			this.elements.each(function(el, i){
				this.now[i] = this.now[i] || {};
				if (i != iToShow){
					this.hideThis(i);
				} else if (this.options.alwaysHide){
					if (el.offsetHeight == el.scrollHeight){
						this.hideThis(i);
						madeInactive = true;
					} else if (el.offsetHeight == 0){
						this.showThis(i);
					} else {
						err = true;
					}
				} else if (this.options.wait && this.timer){
					this.previousClick = 'nan';
					err = true;
				} else {
					this.showThis(i);
				}
				objObjs[i+1] = Object.extend(this.h, Object.extend(this.o, this.w));
			}.bind(this));
			if (err) return;
			if (!madeInactive) this.options.onActive.call(this, this.togglers[iToShow], iToShow);
			this.togglers.each(function(tog, i){
				if (i != iToShow || madeInactive) this.options.onBackground.call(this, tog, i);
			}.bind(this));
			return this.custom(objObjs);
		}
	},
	
	increase: function(){
		for (var i in this.now){
			var iNow = this.now[i];
			for (var p in iNow) this.setStyle(this.elements[parseInt(i)-1], p, iNow[p]);
		}
	}

});
