var CSS = {
	addClass: function(element, klass) {
		if (!CSS.hasClass(element, klass)) element.className += ' ' + klass;
	},
	hasClass: function(element, klass) {
		return new RegExp('\\b' + klass + '\\b').test(element.className);
	},
	toggleClass: function(element, klass) {
		if (CSS.hasClass(element, klass)) {
			CSS.removeClass(element, klass);
		}
		else {
			CSS.addClass(element, klass);
		}
	},
	removeClass: function(element, klass) {
		element.className = element.className.replace(new RegExp('\\b' + klass + '\\b'), '');
	}
};

function GenericCalculator(container, fields) {

	var FORM_ID = 'GnC_' + (function(context) {
		if (context.counter === undefined) {
			return context.counter = 0;
		}
		return ++context.counter;
	})(arguments.callee);
	
	var instance = this;
	
	function format(value, precision) {
		if (value === null || value === undefined || value === '') return '-';
		if (isNaN(value)) return value;
		return Number(value).toFixed(precision);
	}
	
	function calculate() {
		for (var name in fields) {
			if (!fields.hasOwnProperty(name)) continue;
			var field = fields[name], value;
			switch (typeof field.value) {
				case 'function':
					value = Number(field.value.call(instance));
					empty(field.element).appendChild(document.createTextNode(format(value, field.precision || 2)));
					break;
				default:
					value = Number(field.element.value);
					break;
			}
			instance[name] = value;
		}
	}

	function create() {
		var form = document.createElement('form');
		form.method = 'get';
		form.onsubmit = function() {
			calculate();
			return false;
		};
		var table = document.createElement('table');
		var fieldCount = 0;
		for (var name in fields) {
			if (!fields.hasOwnProperty(name)) continue;
			var field = fields[name];
			var id = FORM_ID + fieldCount++;
			var row = table.insertRow(-1);
			var labelCell = row.insertCell(-1);
			labelCell.className = 'label-cell';
			var label = document.createElement('label');
			label.htmlFor = id;
			label.appendChild(document.createTextNode(name));
			labelCell.appendChild(label);
			var valueCell = row.insertCell(-1);
			valueCell.className = 'value-cell';
			switch (typeof field.value) {
				case 'function':
					var calculated = document.createElement('strong');
					field.element = calculated;
					calculated.id = id;
					valueCell.appendChild(calculated);
					break;
				default:
					var input = document.createElement('input');
					field.element = input;
					input.id = id;
					input.type = field.type || 'text';
					input.size = field.size || 4;
					input.maxLength = field.maxLength || 15;
					input.value = field.value;
					input.onblur = calculate;
					valueCell.appendChild(input);
					break;
			}
		}
		form.appendChild(table);
		var actions = document.createElement('p');
		actions.className = 'actions';
		var submit = document.createElement('button');
		try {
			submit.type = 'submit';
		}
		catch (e) {
			submit.onclick = calculate;
		}
		submit.appendChild(document.createTextNode('Calculate'));
		actions.appendChild(submit);
		form.appendChild(actions);
		return form;
	}
	
	function empty(element) {
		while (element.firstChild) element.removeChild(element.firstChild);
		return element;
	}
	
	if (typeof container == 'string') container = document.getElementById(container);
	empty(container).appendChild(create());
	
	calculate();
	
}

function init() {
	var nav = document.getElementById('nav');
	var subs = document.getElementById('nav').getElementsByTagName('ul');
	var secondary;
	for (var node = nav.lastChild; node; node = node.previousSibling) {
		if (/secondary/.test(node.className)) {
			secondary = node;
			break;
		}
	}
	if (!secondary) {
		secondary = document.createElement('ul');
		secondary.className = 'nav secondary empty';
		nav.appendChild(secondary);
	}
	for (var i = 0, l = subs.length; i < l; ++i) {
		if (subs[i].parentNode == nav) continue;
		for (var node = subs[i]; node; node = node.previousSibling) {
			if (node.nodeName.toLowerCase() != 'a') continue;
			node.onclick = function(e) {
				e = e || window.event;
				e.returnValue = false;
				if (e.preventDefault) e.preventDefault();
				for (var li = this.parentNode.parentNode.firstChild; li; li = li.nextSibling) {
					if (li.nodeType != 1) continue;
					CSS.removeClass(li, 'active');
				}
				CSS.addClass(this.parentNode, 'active');
				for (var node = this.nextSibling; node; node = node.nextSibling) {
					if (node.nodeName.toLowerCase() != 'ul') continue;
					secondary.innerHTML = node.innerHTML;
					CSS.removeClass(secondary, 'empty');
				}
			}
			if (/current_page/.test(node.parentNode.className)) {
				CSS.addClass(node.parentNode, 'active');
			}
		}
		for (var li = subs[i].parentNode.parentNode.firstChild; li; li = li.nextSibling) {
			if (li.nodeType != 1) continue;
			if (/current_page/.test(li.className)) CSS.addClass(li, 'active');
			CSS.removeClass(li, 'current_page_item');
			CSS.removeClass(li, 'current_page_parent');
			CSS.removeClass(li, 'current_page_ancestor');
		}
	}
	CSS.addClass(nav.getElementsByTagName('li')[0], 'first');
}
