/* usemedia.com . joes koppers . 06.2007 */
/* thnx for reading this code */


//multi-column text layout (in wait for CSS 3 column-style) 

function ColumnLayout(elm,w,h,g)
{
	this.column_w = w || 330;	//css width
	this.column_h = h || 450;	//css height
	this.column_g = g || 40;	//css padding-left (gap between cols)

	this.parent = elm; 			//container for the columns
	
	//div to hold entire text contents before columnizing
	var div = document.createElement('div')
		div.style.position = 'absolute';
		div.style.width = '0px';
		div.style.height = '0px';
		div.style.display = 'none';
	this.parent.appendChild(div);
	this.src = div;

	this.addTextResizeListener();

	this.content = '';
	this.x = 0;
	this.sliding = false;
	
	//set defaults
	this.rset();
}

ColumnLayout.prototype.rset = function()
{
	this.cols = 0;
	this.parent.style.width = '';
	//clear container, except for resizeListener
	while (this.parent.childNodes.length>2) this.parent.removeChild(this.parent.lastChild);
	//clear src
	this.src.innerHTML = '';

	this.enableTextResizeListener(false);
}

ColumnLayout.prototype.init = function(content)
{
	if (content) this.content = content;
	else
	{
		if (this.content=='') return; //fail
		//re-columnize, clear first
		this.rset();
	}
	
	this.src.innerHTML = this.content;
	this.process();

	this.enableTextResizeListener(true);
}

ColumnLayout.prototype.process = function(target,src)
{
	var fit = true;
	var done = (this.src.innerHTML=='' || (this.src.childNodes.length==1 && this.src.childNodes[0].innerHTML==''))? true:false;

	//processing needed?
	if (done) {	this.done(); return; }

	if (!target) //default, start a new column
	{
		this.col = this.addColumn();
		var target = this.col;
		var src = this.src;
	}

	while (fit = this.col.scrollHeight<=this.column_h)
	{
		if (this.src.childNodes.length==0)
		{
			this.done();
			return;
		}
		if (src.childNodes.length==0) break;
		
		//move src child element to target
		target.appendChild(src.childNodes[0]);
	}
	
	//undo move of last element
	var elm = target.lastChild;
	if (elm) src.insertBefore(elm,src.firstChild);
	else
	{
		this.process();
		return;
	}

	//try and split last element
	switch (elm.nodeName)
	{
		//textNode
		case '#text':
			var txt = elm.nodeValue;
			if (!fit) this.splitTextNode(txt,target,src);
			else 
			{
				target.appendChild(elm);
				this.done();
			}
			break;
		
		//splitable elements
		case 'SPAN':
		case 'I':
		case 'STRONG':
		case 'B':
		case 'P':
		case 'UL':
		case 'EM':
//		case 'FORM':
			//add a clone of this elm to current col (target)
			var clone = elm.cloneNode(false);
			target.appendChild(clone);
			
			//more nested dom elements?
			if (elm.childNodes.length>1)
			{
				//keep on processing with this elm as source
				this.process(clone,elm);
			}
			else
			{
				//split textContent
				if (elm.firstChild) 
				{
					var txt = elm.firstChild.nodeValue;
					if (txt) this.splitTextNode(txt,clone,elm);
					else this.process();
				}
				else this.process(); //empty elm, continue processing
			}
			break;
		
		//non-splitable elements
		case 'DIV':
		case 'BR':
		case 'A':
		case 'OL':
 		case 'LI':
 		case 'INPUT':
 		case 'TEXTAREA':
 		case 'IMG':
 		//case 'FORM':
			//continue with next column
			this.process();
			break;
	}
}

ColumnLayout.prototype.splitTextNode = function(txt,target,src)
{
/*	textNode splitting,
	add word by word to column (target) until targetHeight is reached */

	var words = txt.split(" ");

	//create new textnode at end of current column	
	var node = document.createTextNode('.');
	target.appendChild(node);
	
	if (this.col.scrollHeight>this.column_h)
	{
		//cannot add new line, skip splitting and move on to next column
		target.removeChild(target.lastChild);
	}
	else
	{
		var offset = 0
		for (var i=0; i<words.length; i++)
		{
			if (node.nodeValue=='.') node.nodeValue = words[i]+' ';
			else node.nodeValue += words[i]+' ';
			
			//column height reached?
			if (this.col.scrollHeight>this.column_h) break;

			//keep track of chars used			
			offset+= words[i].length + 1;
		}

		//remove the last added word (if any)
		if (i<words.length) node.nodeValue = node.nodeValue.substring(0,node.nodeValue.length-(words[i].length+1));
		//remove used chars from src element
		src.firstChild.nodeValue = src.firstChild.nodeValue.substr(offset);
	}

	//continue with next column
	this.process();
}

ColumnLayout.prototype.addColumn = function()
{
	var div = document.createElement('div');
		div.className = 'column';
		//div.style.width = this.column_w +'px';
		div.style.height = this.column_h +'px';
		//div.style.marginRight = this.column_g +'px';
		div.style.paddingLeft = this.column_g +'px';
		div.style.width = this.column_w + 'px';

	this.parent.appendChild(div);
	
	this.cols++;
	this.parent.style.width = (this.cols*(this.column_w+this.column_g)) +'px';
	
	return div;
}

ColumnLayout.prototype.done = function()
{
	//extent in object
}


/* sliding animation, can be used in navigating columns */

ColumnLayout.prototype.moveTo = function(x)
{
	this.tx = x || 0;
	this.slide();
}

ColumnLayout.prototype.slide = function()
{
	var obj = this;
	
	//move to target	
	var dx = this.tx-this.x;
	this.x = this.x + .30*(this.tx-this.x);
	
	var update_x = (dx>0 && this.x<this.tx-1) || (dx<0 && this.x>this.tx+1);
	var update_y = false;
	
	if (update_x || update_y)
	{
		this.parent.style.left = this.x +'px';
		//loop
		if (this.sliding) window.clearTimeout(this.sliding);
		this.sliding = window.setTimeout(function() { obj.slide() },40);
	}
	else
	{
		//done, set to exact end target position
		this.x = this.tx;
		this.parent.style.left = this.x +'px';
		
		//call done handler (update nav eg)
		this.done()
	}
}


/* resize handling */

ColumnLayout.prototype.addTextResizeListener = function()
{
	var span = document.createElement('span');
		span.className = 'column';
		span.innerHTML = '&nbsp;';
		span.style.position = 'absolute';
		span.style.visibility = 'hidden';
	this.parent.appendChild(span);
		
	//store base font-size and add event handler for resize
	this.base = span.offsetHeight;
	this.size = span;
}

ColumnLayout.prototype.resizeCheck = function(set)
{
	var s = this.size.offsetHeight;
	if (s!=this.base)
	{
		this.base = s;
		//rebuild columns
		this.init(); 
	}
}

ColumnLayout.prototype.enableTextResizeListener = function(enable)
{
	if (this.listen) window.clearInterval(this.listen)

	var obj = this;
	if (enable)
	{
		this.base = this.size.offsetHeight;
		this.listen = window.setInterval(function() { obj.resizeCheck() }, 150);
	}
}


/* debugging */

function debug()
{
	var t = new Date().getTime();
	var str = t+'> ';
	for (var i=0; i<arguments.length; i++)
	{
		if (arguments[i]=='querytime') str+= ', returned in '+(t-debug_time)+'ms'
		else str+= arguments[i];
	}
	
	document.getElementById('debug').innerHTML = str;
	
	return t;
}
