// CSS3MultiColumn - a javascript implementation of the CSS3 multi-column module
// v1.01 beta - Oct. 10 2005
// Copyright (c) 2005 Cˇdric Savarese <pro@4213miles.com>
// This software is licensed under the CC-GNU LGPL <http://creativecommons.org/licenses/LGPL/2.1/>

// For additional information, see : http://www.csscripting.com/

// Supported Properties: 
// column-count 
// column-width	
// column-gap
// column-rule

// Unsupported Properties: 
// column-rule-width (use column-rule instead)
// column-rule-style (use column-rule instead)
// column-rule-color (use column-rule instead)
// column-span
// column-width-policy
// column-space-distribution


function textDivider() {
	//alert('Development Version');
	var splitableTags = new Array('P','DIV', 'SPAN', 'BLOCKQUOTE','ADDRESS','PRE', 'A', 'EM', 'I', 'STRONG', 'B', 'CITE', 'OL', 'UL', 'LI' );

	if(document.location.search.match('mode=debug')) var isDebug = true;
	else var isDebug = false;
		
	var bestSplitPoint = null; 
	var secondSplitPoint = null;
	var secondSplitBottom = 0;
	
	// INITIALIZATION
//	ut.XBrowserAddEventHandler(window,'load',function() { documentReady = true;  processElements(); } );

	function debug(text) {
	//	alert(text);
	}

	
 	// COLUMN PROCESSING 

	
	function processElement(affectedElement,sectionNumber) {
		//affectedElement.style.visibility = 'hidden';
		var widthUnit;
		var width;
		var column_rule_width = 0;
		
	
		var newHeight = 410;
	//	var column_width = 360; 
		var column_count = Math.ceil((affectedElement.offsetHeight * 1.05) / newHeight);	
		
//		alert('offsetHeight section: ' + (affectedElement.offsetHeight * 1.05) + ', column count section: ' + column_count);
		
		// Create a wrapper
		var wrapper = document.createElement('div'); //affectedElement.tagName
		var pn = affectedElement.parentNode;  
		wrapper = pn.insertBefore(wrapper, affectedElement);
		var elem =  pn.removeChild(affectedElement);
		elem = wrapper.appendChild(elem);
		//wrapper.style.border = "1px solid #F00";
		wrapper.className = elem.className;
		elem.className = "";
		// since all columns will be left-floating we need to clear the floats after them.
		//wrapper.style.overflow = 'auto';

		// Assign the content element a random Id ?
		elem.id = 'page_'+sectionNumber+'_1';
		elem.className = 'page';

//		elem.style.width = column_width.toString() + 'px';
		// Compute Desired Height
//		var newHeight = Math.floor(elem.offsetHeight / column_count)+14;
		
//		if(!wrapper.id) wrapper.id = 'book';
		
		// Find split points (j is the max # of attempts to find a good height with no unsplittable element on the split point.
		var j=1;
		for(var i=1; i < column_count && elem && j < (column_count + 5) ; i++) {
			bestSplitPoint = null;
			secondSplitPoint = null;
			secondSplitBottom = 0;
			findSplitPoint(elem, newHeight*i, wrapper);			
			
			if(isDebug) bestSplitPoint.style.border = "1px solid #00FF00";

			if(bestSplitPoint && !isElementSplitable(bestSplitPoint)) {
					
				//	newHeight = getElementRelativeTop(bestSplitPoint, wrapper) + bestSplitPoint.offsetHeight + 10;
					i=1; // reset the height. Try again.
					debug('reset new Height = '+newHeight + ' relativetop=' + getElementRelativeTop(bestSplitPoint, wrapper) + ' offsetHeight= ' + bestSplitPoint.offsetHeight );
			}			
			else if (!bestSplitPoint) {
				debug("No split point found with " + newHeight); 
			}
			
			j++;
		}

	
		
		//wrapper.style.minHeight = newHeight + 'px';
		//if(document.all && !window.opera)
			//wrapper.style.height = newHeight + 'px';
//		debug('<table><tr><td>Avail. Width</td><td>'+availableWidth+'</td><td>Units</td><td>'+widthUnit+'</td></tr><tr><td>column_width</td><td>'+column_width+'</td><td>column_count</td><td>'+column_count+'</td></tr><tr><td>column_gap</td><td>'+column_gap+'</td><td>column_rule</td><td>'+column_rule+'</td></tr><tr><td>New Height</td><td>' + newHeight + '</td><td></td><td></td></tr></table>'  );
 		
		for(var i=1; i < column_count && elem; i++) {
			// Find the split point (a child element, sitting on the column split point)
			bestSplitPoint = null;
			secondSplitPoint = null;
			secondSplitBottom = 0;
			
					
		//	alert('pagina: ' + i + ', height: ' + newHeight);
			
			findSplitPoint(elem, newHeight, wrapper);
			
		//	alert(bestSplitPoint);
			
			if(bestSplitPoint && isElementSplitable(bestSplitPoint) && elem.id != bestSplitPoint.id) {
				var splitE = bestSplitPoint;				
				if(isDebug) secondSplitPoint.style.border = "1px dotted #00F";
			}
			else {
				var splitE = secondSplitPoint;
			}
			if(!splitE) {
				debug("<hr />No split point found for " + elem.tagName + ' ' + i + ' at ' + newHeight);
				return;
			}
			
			// DEBUG ONLY: SHOW SPLIT ELEMENT
			//debug("split top=" + getElementRelativeTop(splitE, wrapper));
			if(isDebug) splitE.style.border = "1px solid #F00";
			// END DEBUG ONLY: SHOW SPLIT ELEMENT
			
			// Create New Column	
			var newCol = elem.cloneNode(false);
			
			// Set the page/column div id
			newCol.id = 'page_' + sectionNumber + '_' + (i+1);
			newCol.className = 'page';
		//	newCol.style.display = 'none';
		
			
			
			// Insert new column in the document
			elem.parentNode.insertBefore(newCol, elem.nextSibling);


			// Move all elements after the element to be splitted (splitE) to the new column
			var insertPoint = createNodeAncestors(splitE,elem, newCol, 'append');

			var refElement = splitE;			
			while(refElement && refElement.id != elem.id ) {
				var littleSib = refElement.nextSibling;
				while(littleSib) {
					moveNode(littleSib, elem, newCol);
					littleSib = refElement.nextSibling;				
				}
				refElement = refElement.parentNode; 
			}
			
	//		alert(splitE + 'gaat naar splitElement in page' + (i+1) + 'targetHeight: ' + (newHeight - getElementRelativeTop(splitE, wrapper)));
			var strippedLine = splitElement(splitE, newHeight - getElementRelativeTop(splitE, wrapper), elem, newCol);			

			// cleaning emptied elements
			var pn = splitE.parentNode;			
			while(pn && pn.id != elem.id) {
				var n = pn.firstChild;
				while(n) {					
					if((n.nodeType==1 && n.childNodes.length == 0) || 
						(n.nodeType==3 && n.nodeValue.replace(/[\u0020\u0009\u000A]*/,'') == "")) {
						pn.removeChild(n);
						n = pn.firstChild;
					} else {
						n = n.nextSibling;
					}
				}
				pn = pn.parentNode;
			}	
			

			// if text-align is justified, insert &nbsp; to force the justify	
			if(strippedLine) {
			//	splitE = elem.lastChild;
			//	if(splitE && (document.defaultView  && document.defaultView.getComputedStyle(splitE,'').getPropertyValue('text-align')=='justify') ||
			//	   (splitE.currentStyle && splitE.currentStyle.textAlign == 'justify')) {
			//		  var txtFiller = document.createTextNode(' ' + strippedLine.replace(/./g,"\u00a0")); // &nbsp;
			//		  var filler = document.createElement('span');				  
			//		  splitE.appendChild(filler); 		
			//		  filler.style.lineHeight="1px";
			//		  filler.appendChild(txtFiller);
			//	} 
			}

			// move on to split the newly added column
			
			elem = newCol;
			
		}
					
	}
	
	// Find the deepest splitable element that sits on the split point.
	function findSplitPoint(n, newHeight, wrapper) {		
		if (n.nodeType==1) {
			var top = getElementRelativeTop(n, wrapper);
			var bot = top+n.offsetHeight;
		//	alert(top + ', ' + bot);
			if(top < newHeight && bot > newHeight) {
				bestSplitPoint = n;
				if(isElementSplitable(n)) {
					for(var i=0;i<n.childNodes.length;i++) {
						findSplitPoint(n.childNodes[i], newHeight, wrapper);
					}
				}
				return;
			} 
			if(bot <= newHeight && bot >= secondSplitBottom) {
				secondSplitBottom = bot;
				secondSplitPoint = n;
			}
		}
		return;
	}
	
	function isElementSplitable(n) {
		if(n.tagName) {
			var tagName = n.tagName.toUpperCase();			
			for(var i=0;i<splitableTags.length;i++)
				if(tagName==splitableTags[i]) return true;
		}
		return false;
	}
		
	function splitElement(n, targetHeight, col1, col2) {
		
		var cn = n.lastChild;
		while(cn) {
	//		alert('in while loop splitelement');
			// if the child node is a text node 			
			if(cn.nodeType==3) {				
				var strippedText = "dummmy";
				var allStrippedText = "";
				// the +2 is for tweaking.. allowing lines to fit more easily
				while(n.offsetHeight > targetHeight+2 && strippedText!="") {
					// remove lines of text until the splittable element reaches the targeted height or we run out of text.
					strippedText = stripOneLine(cn);
					allStrippedText = strippedText + allStrippedText;
				}
				if(allStrippedText!="") {
					var insertPoint = createNodeAncestors(cn,col1,col2,'insertBefore');
					insertPoint.insertBefore(document.createTextNode(allStrippedText), insertPoint.firstChild);
				} 
				if(cn.nodeValue=="") {
					cn.parentNode.removeChild(cn);
				}
				else 
					break;
			}
			else {
				// move element
				var insertPoint = createNodeAncestors(cn,col1,col2,'insertBefore');
				insertPoint.insertBefore(cn.parentNode.removeChild(cn), insertPoint.firstChild);
			}
			cn = n.lastChild;
		}
		return strippedText; // returns the last line of text removed (used later for forcing the justification)
	}
	

	// stripOneLine()
	// This function removes exactly one line to
	// any element containing text
	// and returns the removed text as a string.
	function stripOneLine (n) {
		// get the text node
		while(n && n.nodeType != 3) 
			n = n.firstChild;
		if(!n) return;
	
		// get the height of the element
		var e = n.parentNode;
		var h = e.offsetHeight;
		
		if(!h) {
			//debug('no height for: ' + e.tagName);
			return "";
		}
	
		// get the text as a string
		var str = n.nodeValue;
		
		// remove a word from the end of the string
		// until the height of the element changes 
		// (ie. a line has been removed)
		var wIdx= n.nodeValue.lastIndexOf(' ');
		while(wIdx!=-1 && e.offsetHeight == h) {			
			n.nodeValue = n.nodeValue.substr(0,	wIdx);
			wIdx = n.nodeValue.lastIndexOf(' ');
			if(wIdx==-1) wIdx = n.nodeValue.lastIndexOf('\n');
			//debug(e.offsetHeight + ' ' + h + ' text=' + n.nodeValue + ' wIdx= ' + wIdx);
		} 
		
		if(e.offsetHeight == h)
			n.nodeValue = "";
		// returns the removed text

		return str.substr(n.nodeValue.length);
	}
	
	// method= 'append'/'insertBefore', relative to col2
	function createNodeAncestors(n,col1,col2,method) {
		var ancestors = new Array;
		var insertNode = col2;
		var pn = n.parentNode;
		while(pn && pn.id != col1.id) {
			ancestors[ancestors.length] = pn;
		//	if(!pn.id) pn.id = 'checkkk';
			pn = pn.parentNode;
		}		
		
		for (var i=ancestors.length-1; i >= 0; i--) {
			
			for(var j=0; j < insertNode.childNodes.length && (insertNode.childNodes[j].nodeType==3 || !insertNode.childNodes[j].className.match(ancestors[i].id+'-css3mc')); j++);

			if(j==insertNode.childNodes.length) { 					
				// Ancestor node not found, needs to be created.				
				if(method=='append')
					insertNode = insertNode.appendChild(document.createElement(ancestors[i].tagName));
				else
					insertNode = insertNode.insertBefore(document.createElement(ancestors[i].tagName),insertNode.firstChild);
				insertNode.className = ancestors[i].className+ ' ' + ancestors[i].id + '-css3mc';
				insertNode.style.marginTop = "0";
				insertNode.style.paddingTop = "0";
				if(insertNode.tagName.toUpperCase() == 'OL' && n.nodeType == 1 && n.tagName.toUpperCase() =='LI') {
					var prevsib = n.previousSibling;
					var count=0;
					while(prevsib) {
						if(prevsib.nodeType==1 && prevsib.tagName.toUpperCase() == 'LI') 
							count++;
						prevsib = prevsib.previousSibling;
					}
					insertNode.setAttribute('start', count);
				}
			} else {
				insertNode = insertNode.childNodes[j];
				if(insertNode.tagName.toUpperCase() == 'OL' && (insertNode.start==-1 || insertNode.start==1) && n.nodeType == 1 && n.tagName.toUpperCase() =='LI') {
					// happens if the tag was created while processing a text node.
					var prevsib = n.previousSibling;
					var count=0;
					while(prevsib) {
						if(prevsib.nodeType==1 && prevsib.tagName.toUpperCase() == 'LI') 
							count++;
						prevsib = prevsib.previousSibling;
					}
					insertNode.setAttribute('start', count);
				}
			}
		}
		return insertNode;
	}
	
	function moveNode(n,col1,col2) {		
		var insertNode=createNodeAncestors(n,col1,col2, 'append');
		var movedNode = insertNode.appendChild(n.parentNode.removeChild(n));
		if(insertNode.id == col2.id && movedNode.nodeType ==1 ) {
			movedNode.style.paddingTop = "0px";
			movedNode.style.marginTop = "0px";
		}
		return movedNode;
	}
	
	
	function getElementRelativeTop(obj, refObj) {
		var cur = 0;
		if(obj.offsetParent) {		
			while(obj.offsetParent) {
				cur+=obj.offsetTop;
				obj = obj.offsetParent;
			}
		}
		var cur2 = 0;
		if(refObj.offsetParent) {		
			while(refObj.offsetParent) {
				cur2+=refObj.offsetTop;
				refObj = refObj.offsetParent;
			}
		}
		return cur-cur2; // + document.body.offsetTop;
	}
	

	// Read out all sections and divide them into pages
	var allDivs = document.getElementById('booklet').getElementsByTagName('div');
	var sn = 1;
	for (var i=0;i<allDivs.length;i++) {
		if (allDivs[i].className == 'section') {			
			processElement(allDivs[i], sn);
			sn++;
		}
	}
	
	
}
/*
window.onload = function () {
	textDivider();
	initReport();
}
 */
// Object Instance
// var css3MC = new CSS3MultiColumn();

