/* By Dave Preece, 7/04/2008 */

// menu = the name of the clickable item which expands contents to its full height
// Set = numerix index of the set this accordian belongs to and affects
/* MenuClickThru = whether the onclick is applied to the root menu.  (Only useful for sites which want to  
open the menu items on category pages etc.  Essentially the javascript is ignored and the href on the menu is used instead */

function Accordian(menu , contents , par  , set , menuClickThru){
	var menuHolder = menu;
	var menuContents = contents;
	var menuClickThrough = menuClickThru == null || menuClickThru == true ? true : false;
	// Custom Event Handlers (public functions)
	var onMotionFinished;
	var onMotionUpdated;
	var onMotionStarted;
	this.onOpen = null;
	this.onClose = null;
	// public vars 
	this.openClass = 'active';
	this.closedClass = null;
	this.slideTime = 300; // The amount of time the animation takes to complete
	this.slideUpdate = 10; // The interval which the animation updates at.  Higher = more jerky, lower = more CPU intensive
	this.properClass = 'menu';
	this.parent = par;
	this.allowPropagation = false;
	
	var countTime = 0;
	var numberOfSlidePositions
	var slidePosition;
	var targetSlide;
	var startSlide;
	var mode; // in or out
	var setID = set;
	var menuInterval;
	
	

	/*	To begin with, the class of the menu should be just for the css version to degrade gracefully.
		Use the proper class property to define the class the animated version of the menu 
	*/	
	
	var alertErrors = true;
	var slideTween;

	this.stopSlide = function(){
		window.clearInterval(menuInterval);
	}
	
	
	
	this.error = function(e){
		if(e && alertErrors){
			console.log(e);
		}
	}
	
	this.init = function(){
	
		
		var host = this;
		this.slideTween = Tween.regularEaseInOut;
		var val = document.getElementById('val');
		
		if(isNaN(setID + 1)){ this.error('Set must be numeric !' + setID); return; }
		
		if(!Accordian.prototype.items){ Accordian.prototype.items = []; }
		
		if(!this.items[setID]){ this.items[setID] = []; }
		
		this.items[setID].push(this);
		
		
		
		// Set the non-CSS version's class
	
		
	
		
		if(!menuContents){
			this.error('No accordian contents found ' + setID);
			return;
		}
		
		menuContents.style.height = '0px';
		
		if(menuClickThrough){
			this.attachEvent(menuHolder , 'click', function(e){ 									
														host.toggle();
													  } , false);
		}
		
	}
	
	this.toggle = function(){
		if(this.mode == 'out'){
			this.slideIn();
			return;
		}
		
		this.slideOut();
	}
	
	
	this.initSlide = function(slStart , slStop){
		this.stopSlide();
		slidePosition = 0;
		this.setNumberOfSlidePositions();
		startSlide = slStart;
		targetSlide = slStop;
		var host = this;
		menuInterval = window.setInterval(function(){host.slide();} , this.slideUpdate);
	}
	
	this.slideOut = function(){
		if(menuContents.scrollHeight == menuContents.clientHeight || mode == 'out'){ return; }
		this.setOpenClass();
		this.callOpenHandler();
		this.callOnMotionStarted();
		this.mode = 'out';
		this.resetCountTime();
		this.initSlide(menuContents.clientHeight , menuContents.scrollHeight);
		this.resetAccordiansInSet();
	}
	
	this.resetAccordiansInSet = function(){
		var acc = this.items[setID];
		
		for(a = 0; a < acc.length; a++){
			if(acc[a] != this){
				acc[a].slideIn();
			}
		}
	}
	
	this.closeAccordiansInSet = function(){
		
		var acc = this.items[setID];
		for(var a = 0; a < acc.length; a++){
			if(acc[a] != this){
					
				acc[a].closeAccordian();
			}
		}
	}
	
	this.callCloseHandler = function(){
		if(this.onClose){
			this.onClose(this);
		}
	}
	
	this.callOpenHandler = function(){
		if(this.onOpen){
			this.onOpen(this);
		}
	}
	
	this.openAccordian = function(){
		
		this.stopSlide();
		this.resetCountTime();
		this.closeAccordiansInSet();
		this.mode = 'out';
		this.callOpenHandler();
		this.setOpenClass();
		
		if(menuContents){
			menuContents.style.height = 'auto';
		}
		// We open the parent accordian here to 'chain' nested accordians
		if(this.parent){
			if(this.parent.openAccordian){
				this.parent.openAccordian();
			}
		}
	}
	
	this.closeAccordian = function(){
		this.stopSlide();
		this.resetCountTime();
		this.mode = 'in';
		
		this.setClosedClass();
		this.callCloseHandler();
	
		if(menuContents){
			menuContents.style.height = '0px';
		}
	}
	
	this.setClosedClass = function(){
		if(this.closedClass){
			
			menuHolder.className = this.closedClass;
		}
	}
	
	this.setOpenClass = function(){
		if(this.openClass){
			menuHolder.className = this.openClass;
		}
	}
		
	
	this.slideIn = function(){
		if(this.mode == 'in'){ return; }
		// this will return auto (then NaN via paeseInt) in safari
		var h = parseInt(menuContents.getStyle('height'));
		
		if(isNaN(h)){
			// this will return 0 if height = auto in IE
			h = menuContents.clientHeight;
		}
		
		this.setClosedClass();
		this.callCloseHandler();
		this.callOnMotionStarted();
		this.mode = 'in';
		this.resetCountTime();
		this.initSlide(h , 0);
	}
	
	this.setNumberOfSlidePositions = function(){
		numberOfSlidePositions = this.slideTime / this.slideUpdate;
	}
		
	this.resetCountTime = function(){
		this.countTime = 0;
	}
	
	/*
	t:Number — Specifies the current time, between 0 and duration inclusive.
 
b:Number — Specifies the initial value of the animation property.
 
c:Number — Specifies the total change in the animation property.
 
d:Number — Specifies the duration of the motion.*/
	
	
	this.slide = function(){
			
			this.countTime += this.slideUpdate;
			var pos = Math.round(this.slideTween(this.countTime , startSlide ,targetSlide - startSlide ,  this.slideTime , 1 , 300 )); 
			this.callOnMotionUpdated();
			
			menuContents.style.height = Math.max(0  , pos) + 'px';
			
			slidePosition++;
			if(slidePosition > numberOfSlidePositions){
				// Sets the height to the actual requested height
				menuContents.style.height = targetSlide + 'px';
				
				this.stopSlide();
				this.callOnMotionFinished();
				
				if(targetSlide > 0){
					// We set the height to auto on completion (if the targetSlide is greater than 0)
					menuContents.style.height = 'auto';
				}
			}
	}
	
	
	// Ev
	this.callOnMotionFinished = function(){
		if(this.onMotionFinished){ this.onMotionFinished(this); }
	}
	
	this.callOnMotionStarted = function(){
		if(this.onMotionStarted){ this.onMotionStarted(this); }
	}
	
	this.callOnMotionUpdated = function(){
		if(this.onMotionUpdated){ this.onMotionUpdated(this); }
	}
	
	this.attachEvent = function(el , ev , funct){
		var host = this;
		
		if(!el){ return; }
		
		if(el.addEventListener){
			el.addEventListener(ev , function(e){
											  if(!host.allowPropagation){
												  e.stopPropagation(); 
												  e.preventDefault(); 
											  }
											  funct();
											  } , false);
			
			return;
		}
		
		if(el.attachEvent){
			// IE - has to have 'on' before event handler functs
			el.attachEvent('on' + ev , function(e){	
													if(!host.allowPropagation){
														e.cancelBubble = true;
														e.returnValue = false;
													}
													funct();
												});
			return;
		}
		
	}
	
	this.getMenuHolder = function(){
		return menuHolder;
	}
	
	this.getMenuContents = function(){
		return menuContents;
	}
	
}

// Use this class instead of the full accordian for accordians with blank menuContents (no children);
// It will stop the insertion of a line height in IE when a blank UL exists.
function EmptyAccordian(menu  , par  , set){
	this.parent = par;
	this.allowPropagation = false;
	this.menuHolder = menu;
	
	var mode; // in or out
	var setID = set;
	
	this.init = function(){
		if(!Accordian.prototype.items){ Accordian.prototype.items = []; }
		
		if(!Accordian.prototype.items[setID]){Accordian.prototype.items[setID] = []; }
		
		Accordian.prototype.items[setID].push(this);
		
	}
	
	this.slideIn = function(){
		this.closeAccordian();
	}
	
	this.openAccordian = function(){
		this.closeAccordiansInSet();
		this.mode = 'out';
		this.setOpenClass();
		this.callOpenHandler();
		if(this.parent){
			if(this.parent.openAccordian){
				this.parent.openAccordian();
			}
		}
	}
	
	this.closeAccordian = function(){
		this.setClosedClass();
		this.callCloseHandler();
		this.mode = 'in';
	}
	
	this.closeAccordiansInSet = function(){
		var acc = Accordian.prototype.items[setID];
	
	if(typeof(acc) !== 'Array'){ return; }
		  
		for(var a = 0; a < acc.length; a++){
			if(acc[a] != this){
				acc[a].closeAccordian();
			}
		}
		
	}
	
	this.getMenuHolder = function(){
		return this.menuHolder;
	}
	
	this.getMenuContents = function(){
		return null;
	}
	
	this.setClosedClass = function(){
		if(this.closedClass){
			menuHolder.className = this.closedClass;
		}
	}
	

	this.setOpenClass = function(){
		if(this.openClass){
			menuHolder.className = this.openClass;
		}
	}
	
	this.callCloseHandler = function(){
		if(this.onClose){
			this.onClose(this);
		}
	}
	
	this.callOpenHandler = function(){
		if(this.onOpen){
			this.onOpen(this);
		}
	}
	
}

