// add  <script> multiColumn = true; numberOfColumns = 3; </script> via CM08 to enable on a page
// numberOfColumns is optional
var numberOfColumns;
var multiColumn;

window.addEvent('load', function() { 
	
	if (multiColumn) {
		
		var myColumns = new MooColumns({ 
			className: 'wrapper',
			gutterWidth: 40, 
			tweak:{x:200,y:0,width:0}, 
			morePrecise:true, 
			numOfColumns:numberOfColumns , 
			colBreaksTrump:true,
			debug:false 
		});
	}
});





/**
 * MooColumns beta [for mootools 1.2]
 * @author Jason J. Jaeger | greengeckodesign.com
 * @version 0.6 
 * @license MIT-style License
 *			Permission is hereby granted, free of charge, to any person obtaining a copy
 *			of this software and associated documentation files (the "Software"), to deal
 *			in the Software without restriction, including without limitation the rights
 *			to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *			copies of the Software, and to permit persons to whom the Software is
 *			furnished to do so, subject to the following conditions:
 *	
 *			The above copyright notice and this permission notice shall be included in
 *			all copies or substantial portions of the Software.
 *	
 *			THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *			IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *			FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *			AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *			LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *			OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *			THE SOFTWARE.
 *	
 *  @changeLog_________________________________________________________________________________
 *  
 *  May 13th 2008:
 *  JJJ - Incremented version to 0.6
 *  	- Fixed bug where I was using mootools 1 way of detecting IE6, now it is compatible with 1.2
 *  	- Added colBreaksTrump option (true by default) which disables the auto-split of content if column-breaks are present, this is 
 *  	  because it can be difficult to predict where the column break is going to end up when the content is auto-split first
 **/
/*
 * In your screen stylesheet:
 *  .multiColumn{ display:block; }
 *  .multiColumn-screen{ display:block; } 
 *  .multiColumn-print{ display:none; }
 *  
 * In your print stylesheet:
 *  .multiColumn{ display:block; }
 *  .multiColumn-screen{ display:none; } 
 *  .multiColumn-print{ display:block; }
 *  
 *  [ Assuming "multiColumn" is your className ]
 */


var MooColumns = new Class({
	options: {
		className:'multiColumn',
       	numOfColumns:2,
		defaultNumOfColumns:2,
		gutterWidth:30,
		gutterClassName:'gutter',
		columnClassName:'column',
		tweak:{x:0,y:0,width:0},
		splittableElements:['p','div','span','ul'],
		morePrecise:true,//setting to false will make script run faster
		tolerance:10,//how far below the target bottom non-splittable elements can hang before they are moved to the next column
		colBreaksTrump:true,
		debug:false
    },
	
	sizerElWrapper:null,
	columnParents:[],
	mooColumnsAreasArr:[],
	
	initialize: function(options){
        this.setOptions(options);
		
		
		if($type(parseFloat(this.options.numOfColumns)) != 'number'){
			this.options.numOfColumns = this.options.defaultNumOfColumns;
		}
		
		
		//create wrapper for sizer elements
		this.sizerElWrapper = new Element('div', {'id': 'sizerElWrapper'	}).injectInside(document.body).setStyles({
			'visibility':'hidden','position':'absolute','display':'block','padding':0,'margin':0,'top':0,'left':0,'width':0,'height':0,'overflow':'hidden'
		});
		
		//choose the column area divs if they have the className in their className (so they can have -number at the end of the className)
		this.columnParents = $(document.body).getElements('*').filter(function(item, index){
 			return item.className.toString().contains(this.options.className);
		}.bind(this));
		
		this.columnParents.each(function(item,index){
			var id = this.getOrSetId($(item));
			var aMooColumnsArea = new MooColumnsArea(this.options,item);
			aMooColumnsArea.setOptions(this.options);
			this.mooColumnsAreasArr[id] = aMooColumnsArea;
			item.className +='-screen';
		}.bind(this));
		
    },

	getOrSetId: function(obj){
		if(!obj.id){
			var d = new Date();
			var milli = d.getMilliseconds().toString();
			var randomNumber = Math.floor(Math.random()*1000);
			if(obj.nodeName){
				obj.id = obj.nodeName.toString() + '-' + milli + randomNumber.toString();
			}else{
				obj.id = "element" + milli + randomNumber.toString();	
			}
		}
		return obj.id;
	}
	
	
});
MooColumns.implement(new Options);
MooColumns.implement(new Events);


var MooColumnsArea = MooColumns.extend({
    options: {
		parentEl:null,
		printEl:null,
		debug:null,
		colBreakDepth:10
	},
	
	columnElsArr:[],
	gutterElsArr:[],
	colWidth:null,
	targetHeight:null,
	tempContentHolder:null,
	sizerEl:null,
	tallest:0,
	unsplittableTags:['td','tr','table','tbody'],
	hasColBreaks:false,
	
	initialize: function(options,parentEl){
		this.setOptions(options);
		this.options.parentEl = parentEl;

		//check it numOfColumns is set in the className, if it is, it overides numOfColumns
		if(this.options.parentEl.className.toString().contains('-')){
			var nameArr = this.options.parentEl.className.toString().split('-');
			this.options.numOfColumns = Math.round( parseFloat(nameArr.getLast()) );
		}
		
		//create sizer element
		this.sizerEl = new Element('div').injectInside($('sizerElWrapper')).setStyles({ 'visibility':'hidden','position':'absolute','display':'block','padding':0,'margin':0,'top':0,'left':0 });
		
		//backup original content into a div for printing and refreshing
		this.options.printEl = new Element('div', {'class':this.options.className +'-print'	}).injectAfter(this.options.parentEl).setHTML(this.options.parentEl.innerHTML);
		
		//determine column width
		var gutterWidthAdjustment = (this.options.gutterWidth - (this.options.tweak.width/2 )) - (this.options.gutterWidth/this.options.numOfColumns);
		
		this.colWidth = Math.round( (this.options.parentEl.getCoordinates().width / this.options.numOfColumns) - gutterWidthAdjustment );
		
		//determine & set target height
		this.sizerEl.setStyle('width', this.colWidth).setHTML( this.options.printEl.innerHTML );
		this.targetHeight = Math.round(this.sizerEl.getCoordinates().height / this.options.numOfColumns );
		
		//create empty columns and gutters
		this.makeWireFrame();
		
		//strip scripts and html comments
		this.options.printEl.set('html',this.options.printEl.get('html').stripScripts().split(/<!--[^(-->)]*-->/).join(""));
		
		//wraps naked text nodes within a <p> tag
		this.wrapTextNodes(this.options.printEl);
		
		//convert 2 concecutive horizontal rules to a span with a class of 'colBreak'
		this.convertColBreaks(this.options.printEl);
		
		//if the column breaks are inside of something, split it
		while(this.options.colBreakDepth > 0){
			this.splitColBreakParents(this.options.printEl);
			this.options.colBreakDepth--;
		}
		
		
		if(this.options.colBreaksTrump === true && this.hasColBreaks){ this.options.morePrecise = false;}
		
		
		//divide the content
		var columnsContentArr;
		if(this.hasColBreaks && this.options.colBreaksTrump){
			//just divide on colBreaks and don't auto split content
			columnsContentArr = this.divideContent2();
		}else{
			columnsContentArr = this.divideContent();
		}
		
		
		//fill the columns
		for(i=0;i<columnsContentArr.length;i++){
			this.columnElsArr[i].setHTML(columnsContentArr[i].innerHTML);
		}
		
		//check for & fix overlap
		if (this.options.morePrecise) { this.shaveColumns(); 	}
		
		//set the heights
		if (!this.options.debug) {
			for (i = 0; i < columnsContentArr.length; i++) {
				if (this.columnElsArr[i].getCoordinates().height > this.tallest) {
					this.tallest = this.columnElsArr[i].getCoordinates().height;
				}
			}
			for (i = 0; i < this.columnElsArr.length; i++) {
				this.columnElsArr[i].setStyle('height', this.tallest);
				this.options.parentEl.setStyle('height', this.tallest);
				if (i < this.columnElsArr.length - 1) {
					this.gutterElsArr[i].setStyle('height', this.tallest);
				}
			}
			
			if(Browser.Engine.trident4){
				this.options.parentEl.getParent().setStyle('height',this.tallest);
			}
		}
		 
	},
	
	makeWireFrame:function(){
		this.options.parentEl.empty();
		for(i=0;i < this.options.numOfColumns;i++){
			//create column
			var colLeft = (i* (this.colWidth + this.options.gutterWidth))+this.options.tweak.x;
			this.columnElsArr[i] = new Element('div', {'class':'column'}).injectInside(this.options.parentEl).setStyles({'display':'block','position':'absolute','left':colLeft,'top':this.options.tweak.y,'width':this.colWidth});
			
			//create gutter	
			if(i < this.options.numOfColumns-1){
				this.gutterElsArr[i] = new Element('div', {'class':'gutter'}).injectInside(this.options.parentEl).setStyles({'display':'block','position':'absolute','left':(colLeft + this.colWidth),'top':this.options.tweak.y,'width':this.options.gutterWidth,'height':this.targetHeight});
				if(this.options.debug){	this.gutterElsArr[i].setStyle('background','yellow');}
			}
			if(this.options.debug){	this.columnElsArr[i].setStyle('background','#eee');	}
		}
		if(this.options.debug){this.options.parentEl.setStyle('background','#ccc');}
	},
	
	convertColBreaks:function(sourceEl){
		var horizontalRules = $(sourceEl).getElements('hr');
		for (var i=0; i<horizontalRules.length; i++) {
			var item =$( horizontalRules[i]);
			
			//<hr /> <hr />
			var case1 = item.getNext() && item.getNext().get('tag') === 'hr';
			
			//<hr /> <br /> <hr />
			var case2 = item.getNext() && 
						item.getNext().get('tag') === 'br' && 
						item.getNext().getNext() && 
						item.getNext().getNext().get('tag') === 'hr';
			
			//<p><hr/></p> <p><hr /></p>
			//since having an hr inside of a paragraph tag is invalid the browser will rearrange
			//things to try to fix it. case3 targets the end result html for FireFox and case4 is for IE7
			var case3 = item.getNext() && 
						item.getNext().get('tag') === 'p' &&
						!item.getNext().get('html') &&
						item.getNext().getNext() && 
						item.getNext().getNext().get('tag') === 'hr';
			
			var case4 = item.getNext() && 
						item.getNext().getNext() &&
						item.getNext().getNext().getNext() &&
						item.getNext().get('tag') === 'p' &&
						item.getNext().getNext().get('tag') === 'p' &&
						item.getNext().getNext().getNext().get('tag') === 'hr' &&
						!item.getNext().get('html') &&
						!item.getNext().getNext().get('html');
			
			if (case4 || case3 || case2 || case1) {
				var colBreak = new Element('span', {'class': 'colBreak'	}).injectBefore(item);
				this.hasColBreaks = true;
			}
			
			
			if(case4){
				item.getNext().getNext().getNext().remove();				
			}
			if(case4 || case3 || case2){
				item.getNext().getNext().remove();	
			}
			
			if( case4 || case3 || case2 || case1){
				item.getNext().remove();
				item.remove();
			}
			
		};
	},
	
	splitColBreakParents:function(sourceEl){
		$(sourceEl).getElements('.colBreak').each(function(item,index){
			if(!item.getParent()){return;}
			if(	!item.getParent().hasClass('wrapper-print') && 	!this.unsplittableTags.contains(item.getParent().get('tag'))	){
				var original = item.getParent();
				var firstHalf = original.clone(false);//the false means the clone will be empty
				if(!firstHalf || firstHalf.hasClass('colBreak')){return;}
				var nodeArr1 = $(original).childNodes;
				var currentNode = nodeArr1[0];
				var currentNodeNumber = 1;
				
				//copy everything before the col break into firstHalf
				while ( currentNode && !currentNode.className || currentNode && currentNode.className != 'colBreak') {
					if(currentNode.parentNode.className && currentNode.parentNode.className.contains('multi')){
						return;
					}
					
					if($type(currentNode) === 'textnode' || $type(currentNode) === 'whitespace'){
						if(firstHalf && firstHalf.innerHTML && currentNode.nodeValue){
							//firstHalf.innerHTML +=currentNode.nodeValue;
							firstHalf.set('html',firstHalf.get('html')+currentNode.nodeValue);
							
							currentNode.parentNode.removeChild(currentNode);

						}else{
							break;
						}
						
					}else{
						$try(function(){
						    currentNode.inject(firstHalf,'bottom');
						});					
						
					}
					currentNodeNumber++;
					currentNode = nodeArr1[currentNodeNumber];
				}
				
				//all that is left in original is the second half of the contents,   
				//so duplicate original and replace the first original with firstHalf
				var secondHalf = original.clone(true,true).inject(original,'after');
				$(firstHalf).replaces($(original));
				
				//now move the col break from the inside of secondHalf to inbetween firstHalf & secondHalf
				if(secondHalf.getElements('.colBreak').length >=1){
					$(secondHalf.getElements('.colBreak')[0]).inject(firstHalf,'after');
				}
					
			}
		}.bind(this));
	},
	
	wrapTextNodes:function(sourceEl){
		var nodeArr = $(sourceEl).childNodes;
		for(i=0; i< nodeArr.length;i++){
			if($type(nodeArr[i]) === 'textnode'){
				var clothes = new Element('p').inject(nodeArr[i],'after').set('html', nodeArr[i].nodeValue );
				nodeArr[i].parentNode.removeChild(nodeArr[i]);
			}
		}
	},
	
	divideContent:function(){
		this.tempContentHolder = new Element('div', {'id':'tempContentHolder'}).setHTML(this.options.printEl.innerHTML).injectInside(document.body).setStyles({'display':'none','position':'absolute'});
		this.sizerEl.empty();
		var columnsContent = [];
		var currentColNum = 0;
		var limit = 1300;
		while(this.sizerEl.getCoordinates().height <= this.targetHeight && $(this.tempContentHolder).getFirst() && limit > 0){
		 	limit--;
			if(!columnsContent[currentColNum]){	columnsContent[currentColNum] = new Element('div');	}
			$(this.tempContentHolder).getFirst().injectInside(this.sizerEl);
			if( this.sizerEl.getCoordinates().height >= this.targetHeight || this.sizerEl.getLast().hasClass('colBreak') ){
				$(columnsContent[currentColNum]).setHTML(this.sizerEl.innerHTML);
				this.sizerEl.empty();
				
				currentColNum++;
				if(currentColNum >= this.options.numOfColumns){currentColNum = this.options.numOfColumns -1;}
				//catch any leftover text nodes and put it at the top of the next column
				if(!columnsContent[currentColNum]){	
					columnsContent[currentColNum] = new Element('div');	
				}
				
				if(!this.tempContentHolder.getFirst()){
					$(columnsContent[currentColNum]).setHTML(this.tempContentHolder.innerHTML + $(columnsContent[currentColNum]).innerHTML);}
				}
		}
		$(columnsContent[currentColNum]).setHTML($(columnsContent[currentColNum]).innerHTML + this.sizerEl.innerHTML);
		this.sizerEl.empty();
		return columnsContent;
	},
	
	divideContent2:function(){
		this.tempContentHolder = new Element('div', {'id':'tempContentHolder'}).setHTML(this.options.printEl.innerHTML).injectInside(document.body).setStyles({'display':'none','position':'absolute'});
		this.sizerEl.empty();
		var columnsContent = [];
		var currentColNum = 0;
		var limit = 1300;
		
		while(currentColNum < this.options.numOfColumns  && limit > 0){
		 	limit--;
			if(!columnsContent[currentColNum]){	columnsContent[currentColNum] = new Element('div');	}
			if (this.tempContentHolder.getFirst()) {
				$(this.tempContentHolder).getFirst().injectInside(this.sizerEl);
			}
			if(  this.sizerEl.getLast().hasClass('colBreak') ){
				$(columnsContent[currentColNum]).setHTML(this.sizerEl.innerHTML);
				this.sizerEl.empty();
				
				currentColNum++;
				if(currentColNum >= this.options.numOfColumns){currentColNum = this.options.numOfColumns -1;}
				//catch any leftover text nodes and put it at the top of the next column
				if(!columnsContent[currentColNum]){	
					columnsContent[currentColNum] = new Element('div');	
				}
				
				if(!this.tempContentHolder.getFirst()){
					$(columnsContent[currentColNum]).setHTML(this.tempContentHolder.innerHTML + $(columnsContent[currentColNum]).innerHTML);
				}
			}
		}
		$(columnsContent[currentColNum]).setHTML($(columnsContent[currentColNum]).innerHTML + this.sizerEl.innerHTML);
		
		
		this.sizerEl.empty();
		
		return columnsContent;
	},
	
	shaveColumns:function(){
		for (i = 0; i < this.columnElsArr.length-1; i++) {
			
			var overlap = this.columnElsArr[i].getCoordinates().height - this.targetHeight;
			var ElementIsSplittable = this.columnElsArr[i].getLast().getTag() && this.options.splittableElements.contains(this.columnElsArr[i].getLast().getTag());
			var original = this.columnElsArr[i].getLast();
			
			if(overlap > 0 && ElementIsSplittable ){	
				var elementTargetHeight = original.getCoordinates().height - overlap + this.options.tolerance;
				var clone = original.clone().injectInside($('sizerElWrapper'));
				clone.empty();
				var limit = 50;
				
				while(limit >0 && original.childNodes.length  && original.getCoordinates().height > elementTargetHeight){
					limit--;
					
					if($type(original.childNodes[original.childNodes.length-1]) === 'textnode' ||$type(original.childNodes[original.childNodes.length-1]) === 'whitespace'){
						//split and move textnodes
						var limit2 = 50;
						var textArr = original.childNodes[original.childNodes.length-1].nodeValue.split(" ");
						
						while ( limit2 > 0 && original.childNodes[original.childNodes.length-1].nodeValue.length >= 0 && original.getCoordinates().height > elementTargetHeight) {
							limit2--;
							//copy last word to clone
							if($defined(textArr.getLast())){	clone.innerHTML = textArr.getLast().toString()+ " " + clone.innerHTML;	}
							
							//remove the last word from the array
							textArr = textArr.filter(function(item, index){	return index < (textArr.length-1) && $defined(item) ;	});
							//set original textnode value to flattened array
							original.childNodes[original.childNodes.length-1].nodeValue = textArr.join(" ");
						}
						if(!$defined(textArr.getLast())){
							//delete last childNode in original
							original.removeChild(original.childNodes[original.childNodes.length-1]);
						}
					}else if($(original.childNodes[original.childNodes.length-1])){
						if($(original.childNodes[original.childNodes.length-1]).hasClass('colBreak') ){
							limit = 0;
						}else{
							$(original.childNodes[original.childNodes.length-1]).injectTop(clone);
							//delete last childNode in original
							//original.removeChild(original.childNodes[original.childNodes.length-1]);
						}
					}	
				}
				
				clone.injectTop(this.columnElsArr[i+1]);
				
			}else if (overlap > this.options.tolerance && !ElementIsSplittable){
				original.injectTop(this.columnElsArr[i+1]);
			}
		}
	}
	
});
MooColumnsArea.implement(new Options);
MooColumnsArea.implement(new Events);