/*
  Columnize Plugin for jQuery
  Version: v0.6

  Copyright (C) 2008 by Systemantics, Bureau for Informatics

  Lutz Issler
  Mauerstr. 10-12
  52064 Aachen
  GERMANY

  Web:    www.systemantics.net
  Email:  mail@systemantics.net

  This plugin is distributed under the terms of the
  GNU Lesser General Public license. The license can be obtained
  from http://www.gnu.org/licenses/lgpl.html.
*/

(function() {
	var cloneEls = new Object();
	var numColsById = new Object();
	var uniqueId = 0;

	function _layoutElement(elDOM, settings, balance) {
		// Some semi-global variables
		var colHeight;
		var colWidth;
		var col;
		var currentColEl;
		var cols = new Array();
		var colNum = 0;
		var colSet = 0;

		var el = jQuery(elDOM);

		// Save numCols property for this element
		// (needed for pagination)
		numColsById[elDOM.id] = settings.columns;

		// Remove child nodes
		el.empty();

		// Macro function (with side effects)
		function _newColumn() {
			colNum++;

			// Add a new column
			col = document.createElement("DIV");
			col.className = settings.column;
			el.append(col);
			currentColEl = col;
			colWidth = jQuery(col).width();
			cols.push(col);

			// Add the same subnode nesting to the new column
			// as there was in the old column
			for (var j=0; j<subnodes.length; j++) {
				newEl = subnodes[j].cloneNode(false);
				if (j==0 || innerContinued) {
					jQuery(newEl).addClass(settings.continued);
				}
				currentColEl.appendChild(newEl);
				currentColEl = newEl;
			}
		}

		// Advance to next sibling on el or a parent level
		function _skipToNextNode() {
			while (currentEl && currentColEl && !currentEl.nextSibling) {
				currentEl = currentEl.parentNode;
				currentColEl = currentColEl.parentNode;
				var node = subnodes.pop();
				// Hack: delete the previously saved HREF
				if (node=="A") {
					href = null;
				}
			}
			if (currentEl) {
				currentEl = currentEl.nextSibling;
			}
		}

		// Take the height from the element to be layouted
		var maxHeight = parseInt(el.css("maxHeight"));
		if (balance || maxHeight==0) {
			// We are asked to balance the col lengths
			// or cannot get the column length from the container,
			// so chose a height that will produce >numCols< columns
			col = document.createElement("DIV");
			col.className = settings.column;
			jQuery(col).append(jQuery(cloneEls[elDOM.id]).html());
			el.append(col);
			var lineHeight = parseInt(el.css("lineHeight"));
			if (!lineHeight) {
				// Assume a line height of 120%
				lineHeight = Math.ceil(parseInt(el.css("fontSize"))*1.2);
			}
			colHeight = Math.ceil(jQuery(col).height()/settings.columns);
			if (colHeight%lineHeight>0) {
				colHeight += lineHeight;
			}
			elDOM.removeChild(col);
			if (maxHeight>0 && colHeight>maxHeight) {
				// Balance only to max-height
				colHeight = maxHeight;
			}
		} else {
			colHeight = maxHeight;
		}

		// Start with first child of the initial node
		var currentEl = cloneEls[elDOM.id].children(":first")[0];
		var subnodes = new Array();
		var href = null;
		var lastNodeType = 0;
		_newColumn();
		if (colHeight==0 || colWidth==0) {
			// We cannot continue with zero height or width
			return false;
		}
		while (currentEl) {
			if (currentEl.nodeType==1) {
				// An element node
				var newEl;
				if (jQuery.inArray("dontsplit", currentEl.className.split(" "))>-1) {
					// Don't split this node. Instead, clone it completely
					var newEl = currentEl.cloneNode(true);
					currentColEl.appendChild(newEl);
					if (col.offsetHeight>colHeight) {
						// The column gets too long, start a new colum
						currentColEl.removeChild(newEl);
						var toBeInsertedEl = newEl;
						_newColumn();
						currentColEl.appendChild(toBeInsertedEl);
					}
					currentEl = jQuery(currentEl).next()[0];
				} else {
					// Clone the node and append it to the current column
					var newEl = currentEl.cloneNode(false);
					currentColEl.appendChild(newEl);
					if (currentEl.firstChild) {
						subnodes.push(currentEl.cloneNode(false));
						currentColEl = newEl;
						currentEl = currentEl.firstChild;
					} else {
						_skipToNextNode();
					}
				}
				lastNodeType = 1;
			} else if (currentEl.nodeType==3) {
				// A text node
				var newEl = document.createTextNode("");
				currentColEl.appendChild(newEl);
				// Append word by word
				var words = currentEl.data.split(" ");
				for (var i=0; i<words.length; i++) {
					if (lastNodeType==3) {
						newEl.appendData(" ");
					}
					newEl.appendData(words[i]);
					if (col.offsetHeight>colHeight) {
						// el column is full
						// Remove the last word
						newEl.data = newEl.data.substr(0, newEl.data.length-words[i].length-1);

						// Remove the last node if empty
						var innerContinued;
						if (jQuery(currentColEl).text()=="") {
							jQuery(currentColEl).remove();
							innerContinued = false;
						} else {
							innerContinued = true;
						}

						// Start a new column
						_newColumn();

						// Add a text node at the bottom level
						// in order to continue the column
						newEl = document.createTextNode(words[i]);
						currentColEl.appendChild(newEl);
					}
					lastNodeType = 3;
				}
				_skipToNextNode();
				lastNodeType = 0;
			} else {
				// Any other node (comments, for instance)
				_skipToNextNode();
				lastNodeType = currentEl.nodeType;
			}
		}
		return cols;
	};

	jQuery.fn.columnize = function(settings) {
		settings = jQuery.extend({
			column: "column",
			continued: "continued",
			columns: 2,
			balance: true
		}, settings);
		this.each(function () {
			var jthis = jQuery(this);

			var id = this.id;
			if (!id) {
				// Get a new id
				id = "jcols_"+uniqueId;
				this.id = id;
				uniqueId++;
			}

			if (!cloneEls[this.id]) {
				cloneEls[this.id] = jthis.clone(true);
			}

			// Layout the columns
			var cols = _layoutElement(this, settings, settings.balance);
			if (!cols) {
				// Layout failed, restore the object's contents
				jthis.append(cloneEls[this.id].children().clone(true));
			}
		});
		return this;
	}
})();
