/*-------- TOGGLER -----------*/

/* 

version .32 -- re-write -- took all the logic and put it in the init(), among other updates;

*/
 
 Toggler = Class.create();
 
 Toggler.prototype = {
	  initialize: function(baseID, options) {

		this.currentShowing = ''
		this.togglers = '';
		this.togglerIDs = [];
	  	this.containerIDs = [];
	  	this.triggerIDs = [];
	  	
	  	
		this.options = {
			
			/* class placed around a single complete member of a Toggler (includes the trigger and the hiding content) - usually a div  */
			togglerWrapperClass : '',
			
			/* the node which gets hidden/shown. */
			toggler: '',
			
			togglerClass: '',
		
			/* the node which shows/hides the toggler */
			trigger: '',
		
			/* base node for the trigger */
			triggerBaseNode : '',
			
			triggerClass: '',
			
			/* node for the trigger when the main thing you click is in a child element of the triggerbaseNode */
			triggerTag : '',
			
			/* use if you want to set a specific node in the triggerBaseNode to be the change indicator - it will receive the on class and be the clickable element depending on the triggerOnly setting below */
			triggerIndicator: '',
			
			/* used if we do a general replacement in a whole base DIV for more than one block of togglers, and we want to use the same baseName for more than one call */
			groupName: '',
			
			/* set this to the first one to open.  Can be an ID or number.  If number, you cannot already have an ID in the HTML.  Passing 'none' keeps them all off at startup */
			first: 0,
			
			/* set this to activate accordian-type toggling */
			accordian: false,
			action: 'click',
			collapsable: true
		}
		
		this.container = $(baseID);
		
		Object.extend(this.options, options || {})
		
		// depricated //
		if (this.options.tagToHide) { this.options.toggler = this.options.tagToHide };
		if (!this.options.triggerBaseNode && this.options.trigger) { this.options.triggerBaseNode = this.options.trigger };
		
		this.init(); 
		
		if (this.options.first != 'none') this.open(this.options.first);
		
	  },
	  
	  init: function() {
	  	
	  	// is the trigger that hides the toggler inside a div wrapper or not? //
	  	this.outside = false;
	  	
	  	// get the togglers //
	  	
	  	// the trigger and the toggler will be wrapped in a div when there is a togglerWrapperClass. //
	  	
	  	if (this.options.togglerWrapperClass) {
	  		var togglers =  this.container.getElementsByClassName(this.options.togglerWrapperClass);
	  	}
	  	else {
	  		if (this.options.toggler || this.options.togglerClass) {
	  			this.outside = true;
	  			var togglers = this.options.togglerClass ? this.container.getElementsByClassName(this.options.togglerClass) :
	  			this.container.getElementsByTagName(this.options.toggler);
	  		}
	  		
	  		else {
	  			//using a selector //
	  			var togglers = $$(this.options.togglerSelector);
	  		}
	  	}
	
		this.togglers = togglers;
	
		// got the togglers //
	
		var groupName = this.options.groupName || this.container.id;
	
		this.groupName = groupName;
	
		for(var x = 0; x < togglers.length; x++) {
		
				if (!togglers[x].id) {
					this.containerIDs[x] = togglers[x].id = groupName + '-toggler-wrapper-' + x;
				}
				
				// figure out the triggers //
				
				if (!this.outside) {		
					
					var triggers = this.options.triggerClass ? 
					togglers[x].getElementsByClassName(this.options.triggerClass) :
					togglers[x].getElementsByTagName(this.options.triggerBaseNode);				
					
					if (triggers.length > 1 && !this.options.triggerClass) {
						alert('You gotta set a triggerClass so you can pick a certain trigger node inside yo wrappers!');
						break;
					}
					
					var target = this.options.triggerTag ? 
					triggers[0].getElementsByTagName(this.options.triggerTag)[0] :
					triggers[0];
				}

				// the trigger is not inside a wrapper element.  Let's make it either the previous or next sibling //
				else {
					
					$(togglers[x].parentNode).cleanWhitespace();
					var target = this.options.orientation == 'next' ? togglers[x].nextSibling : togglers[x].previousSibling;
					
				}
				
				if (!target.id) target.id = groupName + '-toggler-tr-' + x;
				
				this.triggerIDs[x] = target.id;
				
				target.style.cursor = 'pointer';
				target.style.outline = 'none';
				
				// add the click //
				Event.observe(target, this.options.action, this.open.bindAsEventListener(this));
				
				// done triggers //
				
				var contentToHide = this.options.togglerClass ? togglers[x].getElementsByClassName(this.options.togglerClass) :
				togglers[x].getElementsByTagName(this.options.toggler);
	
				if (contentToHide.length > 1 && !this.options.togglerClass) {
						alert('you gotta set a togglerClass so you can pick a certain toggler node inside yo wrappers!');
						break;
					}
	
				// set contentToHide to the tagName inside the wrapper -- otherwise set it to the toggler itself //
				contentToHide = contentToHide[0] ? contentToHide[0] : togglers[x];
				
				if (!contentToHide.id) {
					contentToHide.id = groupName + '-toggler-' + x;
				}
				
				this.togglerIDs[x] = contentToHide.id;
				// hide the contentToHides //
				
				$(contentToHide).style.display = 'none';
			}	
		
	  },
	  
	  
	 getBase: function(id) { // takes an element or ID, returns element //
		
			// getBase returns the node which is the wrapper for the trigger //
			
				// otherwise, get the node that will hold the on class //
				if (this.options.triggerBaseNode) {
					var t = $(id).tagName
					var parent = $(id);
					
					// two modes.  if we use a triggerTag, the id will be placed on the tag - not on the wrapper div.  so we gotta check. //
					
					while( (t != this.options.triggerBaseNode.toUpperCase() ) 
					|| ((this.triggerIDs.indexOf(parent.id) == -1 && !this.options.triggerTag) ) ) {
				
						parent = parent.parentNode
						t = parent.tagName
						
						
					}
					return $(parent);
				}
				
				// otherwise, the trigger is the node //
				else {
					return $(id);
				}
			
		},
	  
	  changeIndicator: function(base) {
	  
	  		if (this.options.triggerIndicator) {
	  			var changer = $(base).getElementsByTagName(this.options.triggerIndicator)[0];
	 			(changer.className == 'on') ? changer.removeClassName('on') : $(changer).addClassName('on');
	 		}
	 		else {
	 			(base.hasClassName('on')) ? $(base).removeClassName('on') : $(base).addClassName('on');
	 		}
	 		
	 },
	 
	  open: function(e) {
	  
	  	if (this.showing || this.hiding) { Event.stop(e); return false }
		
		switch (typeof e) {
				case 'number' :
					var clickedTarget = $(this.groupName + '-toggler-tr-' + e);
					break;
				case 'string' :
					var clickedTarget = $(e);
					break;
				default:
					var clickedTarget = Event.element(e);
					break;
		}
		
			var trigger = this.getBase(clickedTarget);
		
			var index = this.options.triggerTag ? this.triggerIDs.indexOf(clickedTarget.id) : this.triggerIDs.indexOf(trigger.id);
			
			var contentToShow = $(this.togglerIDs[index]);
			
		
		if(this.options.accordian) {
		
			if (contentToShow.id != this.currentShowing) {		
				
				// use currentShowing in the method to find the node and close it //
				this.closeCurrent();
				
				if (typeof this.options.beforeShow == 'function') {
					this.options.beforeShow.apply(this, ['show', contentToShow, trigger]);
				}
				
				this.changeIndicator(trigger);	
				this.show(contentToShow);
		
				this.currentShowing = contentToShow.id;
			}
			
			else {
				if (this.options.collapsable) {
					this.closeCurrent();
					this.currentShowing = 0;
				}
			}
			
			
		}
		
		// just open and close the boxes without accordian //
		// TODO: add in looping through multiple triggerId contentnodes //
		else {
		
				if (contentToShow.style.display == 'block' ) {
	
					this.changeIndicator(trigger);	
					
					if (typeof this.options.beforeHide == 'function')
						this.options.beforeHide.apply(this, ['hide', contentToShow, trigger]);
					
					this.hide(contentToShow);
	
				}
				else {
	
					this.changeIndicator(trigger);	
					
					if (typeof this.options.beforeShow == 'function')
						this.options.beforeShow.apply(this, ['show', contentToShow, trigger]);
					
					this.show(contentToShow);
	
				}
			}
		
		Event.stop(e);
		  
	  },
	  
	  closeCurrent: function() {
		  
		  if(this.currentShowing || !this.options.accordian) {
				
				var contentToHide = $(this.currentShowing);
				
				var index = this.togglerIDs.indexOf(this.currentShowing);
				var trigger = this.getBase($(this.triggerIDs[index]));
				this.changeIndicator($(trigger));
				
				if (typeof this.options.beforeHide == 'function')
					this.options.beforeHide.apply( this, ['hide', contentToHide, trigger]);
		  	
		  		this.hide(contentToHide);
		  
		  }
	  },
	 
	 
	  show: function(el) {
	  
	  		if (this.options.slide && el.style.display == 'none' ) {
	  			this.showing = Effect.BlindDown(el, {  duration: .5,
	  								    	afterFinish: function() { this.showing = null }.bind(this)
	  								 });
	  		}
	  		else {
	  			el.style.display = 'block';
	  		}
	  },
	 
		  
	  hide: function(el) {
	  		if (this.options.slide && el.style.display == 'block') {
	  			this.hiding = Effect.BlindUp(el, {duration: .5,
	  												afterFinish: function() { this.hiding = null }.bind(this)
	  			});
	  		}
	  		else {
	  			el.style.display = 'none'
	  		}
	  			
	  },
	  
	  all: function(e, type) {
	  	
	  			/* default is 'on' */
	  			if (arguments.length == 2) Event.stop(e);
	  			else type = e;

	  			for(var x = 0; x < this.togglers.length; x++) {
	  			
	  				var triggerBaseNode = this.getBase(this.triggerIDs[x]);
					var trigger = $(triggerBaseNode);
				
					var contentToHide = $(this.togglerIDs[x]);
				
					
					(type == 'off' || type == 'hide') ? this.hide(contentToHide) : this.show(contentToHide);
					
					if ((contentToHide.style.display == 'none') && (type != 'off' && type != 'hide')) {
						this.changeIndicator(trigger);	
					}
					if ((contentToHide.style.display == 'block') && (type == 'off' || type == 'hide')) {
						this.changeIndicator(trigger);	
					}
					
					this.currentShowing = 'none';
					this.options.accordian = false;
					
				}
				
				
				
		}	  
	 
}

// overwrite prototype's show method to specifically add block -- necessary if we want to use Effect.Appear and hide the background with CSS display: none; //

var newShow = { show : function(element) {
	$(element).style.display = 'block';
	return element;
  	}
  }
// 
Element.addMethods(newShow);
