/*	name			: ClassBehaviours, the javascript framework based on class-name parsing	update			: 9.2.2	author			: Maurice van Creij	dependencies	: jquery.classbehaviours.js	info			: http://www.classbehaviours.com/

    This file is part of jQuery.classBehaviours.
    
    ClassBehaviours is a javascript framework based on class-name parsing.
    Copyright (C) 2008  Maurice van Creij

    ClassBehaviours is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    ClassBehaviours is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with ClassBehaviours. If not, see http://www.gnu.org/licenses/gpl.html.*/

	// create the jQuery object if it doesn't already exist
	if(typeof(jQuery)=='undefined') jQuery = function(){};
	
	// create the root classbehaviours object if it doesn't already exist
	if(typeof(jQuery.classBehaviours)=='undefined') jQuery.classBehaviours = function(){};
	
	// create the handlers child object if it doesn't already exist
	if(typeof(jQuery.classBehaviours.handlers)=='undefined') jQuery.classBehaviours.handlers = function(){}

	// show or hide a node
	document.writeln("<style>.toggleNextNode{cursor:pointer;}</style>");
	jQuery.classBehaviours.handlers.toggleNextNode = {
		// properties
		name: 'toggleNextNode',
		step: 10,
		acceleration: 10,
		extra: 0,
		delay: 10,
		index: 0,
		// methods
		start: function(node){
			// set the event handlers for the source node
			node.onclick = this.toggle;
			// give this node an id if it doesn't have one yet
			node.id = (node.id) ? node.id : this.name + this.index++ ;
			// is this node marked as "auto", order it to open on a timeout
			autoDelay = jQuery.classBehaviours.utilities.getClassParameter(node, 'auto', null);
			if(autoDelay){
				this.index++
				node.id = (node.id) ? node.id : this.name + this.index ;
				setTimeout('jQuery.classBehaviours.handlers.toggleNextNode.toggle(document.getElementById("'+node.id+'"))', autoDelay);
			}
		},
		findContainer: function(targetLabel, targetRecursion){
			var t2n = jQuery.classBehaviours.handlers.toggleNextNode;
			// if there was a target recursion, recurse parent nodes
			if(targetRecursion) for(var a=0; a<parseInt(targetRecursion); a++) targetLabel = targetLabel.parentNode;
			// get the next sibling of the label, which should be the container
			targetObject = jQuery.classBehaviours.utilities.nextNode(targetLabel);
			// give it an ID for reference
			targetObject.id = (targetObject.id) ? targetObject.id : t2n.name + 'Target' + t2n.index++;
			// pass it back
			return targetObject;
		},
		positionContainer: function(targetContainer, screenXpos, screenYpos){
			// if the position is too close to the edge
			targetContainerWidth = targetContainer.firstChild.offsetWidth;
			screenWidth = (window.innerWidth) ? window.innerWidth : document.documentElement.clientWidth ;
			scrolledWidth = (typeof(document.documentElement.scrollLeft)!='undefined') ? document.documentElement.scrollLeft : window.pageXOffset ;
			if(screenXpos+targetContainerWidth > screenWidth+window.pageXOffset) screenXpos -= targetContainerWidth;
			// if the position is too close to the bottom
			targetContainerHeight = targetContainer.firstChild.offsetHeight;
			screenHeight = (window.innerHeight) ? window.innerHeight : document.documentElement.clientHeight ;
			scrolledHeight = (typeof(document.documentElement.scrollTop)!='undefined') ? document.documentElement.scrollTop : window.pageYOffset ;
			if(screenYpos+targetContainerHeight+10 > screenHeight+scrolledHeight) screenYpos -= targetContainerHeight;
			// set the position
			targetContainer.style.left = screenXpos + 'px';
			targetContainer.style.top = screenYpos + 'px';
		},
		// events
		toggle: function(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			var t2n = jQuery.classBehaviours.handlers.toggleNextNode;
			// get all information on this node
			targetLabel = objNode;
			targetContainerId = jQuery.classBehaviours.utilities.getClassParameter(targetLabel, 'id', null);
			targetRecursion = jQuery.classBehaviours.utilities.getClassParameter(targetLabel, 'parent', null);
			targetClosable = (jQuery.classBehaviours.utilities.getClassParameter(targetLabel, 'closable', 'yes') == 'yes');
			targetAtMouse = (jQuery.classBehaviours.utilities.getClassParameter(targetLabel, 'atmouse', 'yes') == 'yes');
			targetContainer = (targetContainerId) ? document.getElementById(targetContainerId) : t2n.findContainer(targetLabel, targetRecursion) ;
			// if the target container is not marked for hiding or showing, mark it now
			if(targetContainer.className.indexOf('hideThisNode')<0 && targetContainer.className.indexOf('showThisNode')<0) targetContainer.className += ' showThisNode' ;
			// call for the node to grow or shrink
			targetGrows = (targetContainer.className.indexOf('hideThisNode')>-1);
			if(!targetGrows && targetClosable || targetGrows) t2n.update(targetLabel.id, targetGrows);
			// position the node at the mouse' position if needed
			if(targetAtMouse && targetGrows){
				// get the position
				screenXpos = (typeof(event)!='undefined' && document.all) ? event.x : that.layerX ;
				screenYpos = (typeof(event)!='undefined' && document.all) ? event.y : that.layerY ;
				// set the position
				t2n.positionContainer(targetContainer, screenXpos, screenYpos);
			}
			// cancel the click
			return false;
		},
		update: function(id, grows){
			var t2n = jQuery.classBehaviours.handlers.toggleNextNode;
			// get all information on this node
			targetLabel = document.getElementById(id);
			targetContainerId = jQuery.classBehaviours.utilities.getClassParameter(targetLabel, 'id', null);
			targetFamily = jQuery.classBehaviours.utilities.getClassParameter(targetLabel, 'family', null);
			targetRecursion = jQuery.classBehaviours.utilities.getClassParameter(targetLabel, 'parent', null);
			targetContainer = (targetContainerId) ? document.getElementById(targetContainerId) : t2n.findContainer(targetLabel, targetRecursion) ;
			// get all nodes of this class
			allNodes = jQuery.classBehaviours.utilities.getElementsByClassName(t2n.name);
			// for every node in the node-list
			for(var a=0; a<allNodes.length; a++){
				// get its properties
				peerLabel = allNodes[a];
				peerContainerId = jQuery.classBehaviours.utilities.getClassParameter(peerLabel, 'id', null);
				peerFamily = jQuery.classBehaviours.utilities.getClassParameter(peerLabel, 'family', null);
				peerRecursion = jQuery.classBehaviours.utilities.getClassParameter(peerLabel, 'parent', null);
				peerContainer = (peerContainerId) ? document.getElementById(peerContainerId) : t2n.findContainer(peerLabel, peerRecursion) ;
				// TARGET: if this node has the same id and is open
				if(peerLabel.id==targetLabel.id){
					// prepare the container
					peerContainer.style.overflow = 'hidden';
					peerContainer.style.visibility = 'visible';
					// open or close the container
					if(!grows)	jQuery.classBehaviours.fader.size(peerContainer.id, null, 1, t2n.step, t2n.delay, t2n.acceleration, 'jQuery.classBehaviours.handlers.hideThisNode.start(document.getElementById("'+peerContainer.id+'"))');
					else		jQuery.classBehaviours.fader.size(peerContainer.id, 1, null, t2n.step, t2n.delay, t2n.acceleration, 'jQuery.classBehaviours.handlers.showThisNode.start(document.getElementById("'+peerContainer.id+'"))');
					// activate the link
					peerLabel.className = (!grows) ? peerLabel.className.replace('active', 'link') : peerLabel.className.replace('link', 'active');
				}
				// PEERS: if this node belongs to the same family and is open but has a different id
				if(peerFamily==targetFamily && peerFamily!=null && peerContainer.className.indexOf('hideThisNode')<0 && peerContainer!=targetContainer){
					// prepare the container
					peerContainer.style.overflow = 'hidden';
					peerContainer.style.visibility = 'visible';
					// close the container
					jQuery.classBehaviours.fader.size(peerContainer.id, null, 1, t2n.step ,t2n.delay, t2n.acceleration, 'jQuery.classBehaviours.handlers.hideThisNode.start(document.getElementById("'+peerContainer.id+'"))');
					// de-activate the link
					peerLabel.className = peerLabel.className.replace('active', 'link');
				}
			}
		}
	}
	
	// hide the "hideThisNode" class behaviour by default 
	document.writeln("<style>.hideThisNode{overflow:hidden; visibility:hidden; height:1px;}</style>");
	jQuery.classBehaviours.handlers.hideThisNode = {
		// properties
		name: 'hideThisNode',
		// methods
		start: function(node){
			node.style.overflow = 'hidden';
			node.style.visibility = 'hidden';
			node.style.height = '1px';
			node.className = node.className.replace('showThisNode', 'hideThisNode');
		}
	}
	
	// explicit opposite of a hidden node
	document.writeln("<style>.ShowThisNode{overflow:visible; visibility:visible; height:auto;}</style>");
	jQuery.classBehaviours.handlers.showThisNode = {
		// properties
		name: 'showThisNode',
		// methods
		start: function(node){
			node.style.overflow = 'visible';
			node.style.visibility = 'visible';
			node.style.height = 'auto';
			node.className = node.className.replace('hideThisNode', 'showThisNode');
		}
	}
			
	// add this addon to the jQuery object
	if(typeof(jQuery.fn)!='undefined'){
		// extend jQuery with this method
		jQuery.fn.toggleNextNode = function(){
			return this.each(
				function(){
					jQuery.classBehaviours.handlers.toggleNextNode.start(this);
				}
			);
		};
		// extend jQuery with this method
		jQuery.fn.hideThisNode = function(){
			return this.each(
				function(){
					jQuery.classBehaviours.handlers.hideThisNode.start(this);
				}
			);
		};
		// extend jQuery with this method
		jQuery.fn.showThisNode = function(){
			return this.each(
				function(){
					jQuery.classBehaviours.handlers.showThisNode.start(this);
				}
			);
		};
		// set the event handler for this jQuery method
		$(document).ready(
			function(){
				$(".toggleNextNode").toggleNextNode();
				$(".hideThisNode").hideThisNode();
				$(".showThisNode").showThisNode();
			}
		);
	}

