// .wounded. software namespace (http://www.magnificent-tears.com/wounded)
var overwrite = Wounded;
var Wounded = {
	toString: function(){ return '[.Wounded. javascript library]'; },
	$: function(element){ return (typeof element == 'string' ? document.getElementById(element) : element); },
	onloads: [function(){ Wounded.document_loaded = true; }], // stack for body onload function references
	onunloads: [], // stack for body onunload
	// add_onload(functionname) : add code block to stack to be fired on window load
	add_onload: function(func){ this.onloads.push(func); if(!window.onload || this.onloads.length == 1){this.set_onload();}},
	set_onload: function(){
		Wounded.map(['onload', 'onunload'],
			function(event){ window[event] = Wounded.bind(function(e){ Wounded.map(Wounded[e+"s"], function(func){func();}) }, event); } );
	},
	add_onunload: function(func){ this.onunloads.push(func);if(!window.onunload || this.onunloads.length == 1){this.set_onload();}},
	// some unit functions
	numeric: function(val, whole){ 
			var newval = val.toString(); //(val.toString().replace(/^\$/, ''));
			newval = (whole ? parseInt(newval) : parseFloat(newval) );
			return ( isNaN(newval) ? 0 : newval );
		},
	forceInt: 	function(val){ return Wounded.numeric(val, true ); },
	forceFloat: function(val){ return Wounded.numeric(val, false); },
 	// return given size(number or string (w/ or w/o px)) with 'px' appended (for CSS)
	px: function(size){ return (parseInt(size.valueOf().toString()).toString() + "px"); },
 	// if less than a hundred (or second argument), assume seconds, otherwise, milliseconds
	ms: function(sec){ return (sec < (arguments.length > 1 ? arguments[1] : 100) ? sec * 1000 : sec); },
	// nbsp(string) == string with spaces converted to an '&nbsp;' (or an emptpy or null string becomes 1 '&nbsp;')
	nbsp: function(str){ return (str ? str.replace(/ /g, '&nbsp;') : '&nbsp;'); },
	ucfirst: function(str){ return str.substr(0,1).toUpperCase() + str.substr(1); },
	// get the attribute value(s) from an xml object whether it's an attribute of the tag or a child element
	xmlval: function(tag, attr){
				var val = tag.getAttribute(attr);
				if(val != undefined)
					return val;
				val = tag.getElementsByTagName(attr)[0];
				if(val.childNodes[0].nodeValue != undefined) // nodeTypes: 3 text
					return val.childNodes[0].nodeValue;
				if(val.textContent != undefined)
					return val.textContent;
				return null;
			},
	newtag: function(tagname, attributes){ var tag;
				if(tagname){
					tag = this.extend(document.createElement(tagname), attributes);
					for(var j=2; j<arguments.length; ++j)
						tag.appendChild(this.newtag.apply(this, arguments[j]));
						//tag.appendChild(this.newtag(arguments[j][0], arguments[j][1], arguments[j][2]));
				}else{
					tag = document.createTextNode(attributes);
				}
				return tag;
			},
	// if first item is defined, use it, else, fall back to second item; defined_or(questionable, literal);
	defined_or: function(conditional, other){ return (conditional != undefined ? conditional : other); },
	// script.aculo.us wrappers
	current_effects: [], // stack for Effect.Something calls (script.aculo.us)
	// add element to effect stack: new_effect('Effect',element, options);
	new_effect: function(effect, element, options){ current_effects.push(new Effect[effect]($(element), options)); },
	// clear all old effects: cancel_current_effects();
	cancel_current_effects: function(){
			return this.map(this.current_effects, function(effect, i){
				if(current_effects[i].cancel){ current_effects[i].cancel(); current_effects.splice(i,1); }});
				return current_effects.length;
		},
	extend: function(abomination, goodness){
			//Wounded.debug('<b>extending</b>', abomination + ' -> ' + goodness)
			for(var i in goodness){
				//Wounded.debug(i, goodness[i]);
				if(typeof(goodness[i]) == 'object'){
					if(typeof(abomination[i]) != 'object')
						abomination[i] = {};
					this.extend(abomination[i], goodness[i]);
				}else{
					try{ abomination[i] = goodness[i]; } catch(e){ /* alert(i + ' -> ' + goodness[i]); */ }
				}
			}
			return abomination;
		},
	leech: function(from, to, prop){ return to[prop] = from[prop]; },
	// thanks to Ed Ball (http://www.ejball.com/EdAtWork/CategoryView,category,JavaScript.aspx)
	bind: function(){
			var after = (typeof(arguments[0]) == 'function' ? 0 : 1)
			var func = arguments[after], args = [];
			for(var i=(after+1); i<arguments.length; ++i)
				args.push(arguments[i]);
			return function (){
				var in_args = [];
				for(var j=0; j<arguments.length; ++j)
					in_args.push(arguments[j]);
				var options = (after ? in_args.concat(args) : args.concat(in_args));
				return func.apply(this, options); //return func.apply(this, (after ? args.concat(in_args) : in_args.concat(args)) );
			};
		},
	bindthis: function(that, func){ return Wounded.bind(function(that, func){return that[func]();}, that, func); },
	push: function(arr){ for(var i=1; i<arguments.length; ++i) arr[arr.length] = arguments[i]; return arr; },
	slice: function(obj, start, end){ var arr=[], j=-1; for(var i=start; i<(end||obj.length); ++i) arr[++j] = obj[i]; return obj; },
	// do something to a bunch of tags that match a certain criteria; do_to_tags("div", conditionfunc, actionfunc, actionargs, starttag);
	do_to_tags: function(tag, condition, action, options, root){
			var tags = (root || document).getElementsByTagName(tag), returns = [];
			for(var i=0; i<tags.length; ++i){
				if(condition(tags[i])){
					returns[returns.length] = action(tags[i], options);
				}
			} return returns;
		},
	find_next_relation: function(element, tag, relation){
		return ( element[relation].nodeName.toLowerCase() == tag.toLowerCase() ? element[relation] :
			Wounded.find_next_relation(element[relation], tag, relation) );
	},
	find_sibling: function(element, tag){ return Wounded.find_next_relation(element, tag, 'nextSibling'); },
	find_ancestor: function(element, tag){ return Wounded.find_next_relation(element, tag, 'parentNode'); },
	getOffset: function(element, axis, size){ axis = axis.replace(/^(.)(.+)$/, RegExp.$1.toUpperCase() + RegExp.$2.toLowerCase());
		return (element && element['offset' + axis] != undefined ?
			((element['offsetParent'] ? Wounded.getOffset(element['offsetParent'], axis) : 0)
			+ element['offset' + axis] + (size ? element['offset' + (axis == 'Left' ? 'Width' : 'Height')] : 0) ) : 0); },
	sprintf: function(format){
			var str = format.split('');
			var s = -1, a = 0;
			var slen = str.length;
			while(++s<slen){
				if( str[s] == '%' ){
					switch(str[s+1]){
					case 's':
						str[s] = arguments[++a];
						break;
					case '%':
						break;
					default: 
						throw Error("Invalid format specifier: %"+ str[s+1]);
						return null;
						continue;
					}
					str[s+1] = '';
				}
			}
			return str.join('');
		},
	style_access_key: function(element){
			var accesskey = (arguments.length > 1 && typeof arguments[1] == 'string' ? arguments[1] : element.accessKey);
			var prop = (element.innerHTML ? 'innerHTML' : 'value');
			var tag = ['<u class="accesskey">', '$1', '</u>'];
			if(accesskey)
				if(element[prop].indexOf(tag[0]) < 0)
					return element[prop] = element[prop].replace(new RegExp('('+accesskey+')', "i"), tag.join('') );
			return false;
		},
	style_access_keys: function(){
			if( document.links.length )
				Wounded.map(document.links, Wounded.style_access_key);
			if( document.forms.length )
				Wounded.map(document.forms,
					function(f){ Wounded.map(f.elements, function(e,i){
						if(e.nodeName.toLowerCase() == 'button')
							return Wounded.style_access_key(e);
						else if(e.nodeName.toLowerCase() == 'input' && e.type == 'text')
							for(var j=i; j<e.form.elements.length; ++j)
								if(e.form.elements[j].nodeName.toLowerCase() == 'button' || e.form.elements[j].type == 'button')
									return Wounded.style_access_key(e.form.elements[j], e.accessKey);
						return false;
					}); }
				);
			return true;
		},
	dev_null: function(){ return null; },
	swallow: function(){ return Wounded.try_catch(Wounded.dev_null, arguments); },
	cry:     function(){ return Wounded.try_catch(Wounded.alert,    arguments); },
	try_catch: function(onerr, funcs){ return Wounded.map(funcs,
			Wounded.bind(function(err, func){ try{ return func(); }catch(e){ err(e); }; return null; }, onerr)) || null; },
	// do func to each item in the array and return the modified array (optionally with nulls/undefineds removed)
	map: function(arr, func, compact){
			var returns = [];
			if( arr.length )
				for(var i=0; i<arr.length; ++i)
					returns[returns.length] = func(arr[i], i);
			else
				for(var i in arr)
					returns[returns.length] = func(arr[i], i);
			if(compact){
				var compacted = [];
				for(var j=0; j<returns.length; ++j)
					if(returns[j] != null && returns[j] != undefined)
						compacted[compacted.length] = returns[j];
				return compacted;
			}else{
				return returns;}
			},
	xmlHttp: false,
	ajaxed: function(xmlhttp){ return (xmlhttp.readyState == 4 && xmlhttp.status == 200); },
	ajax: function(url, opts){ if( Wounded.xmlHttp ){ try{
				var options = Wounded.extend({
						action: null,
						asynchronous: true,
						data: null,
						method: 'GET',
						response: null, //'text/xml',
						statechange: null,
						type: 'application/x-www-form-urlencoded',
						update: null
					}, opts);
				var xmlhttp = new Wounded.xmlHttp();
				// wrappers for common actions
				if( options.update )
					options.action = Wounded.bind(function(id){ $(id).innerHTML = xmlhttp.responseText; }, options.update);
				if( options.action )
					options.statechange = Wounded.bind(function(func){ if( Wounded.ajaxed(xmlhttp) ){ func(xmlhttp); } }, options.action);

				if( xmlhttp.overrideMimeType && options.reponse ) xmlhttp.overrideMimeType('text/xml');
				xmlhttp.onreadystatechange = options.statechange;
				//xmlhttp.setRequestHeader('Content-Type', options.type);
				xmlhttp.open(options.method, url, options.asynchronous);
				xmlhttp.send(options.data);
				return true;
			}catch(e){ alert('xmlhttp: ' + e); } return false; }
			},
	bugger: {autoclose: true},
	debug: function(name, val){
			if( ! Wounded.bugger.window || ! Wounded.bugger.window.document ){ //initialize
				Wounded.bugger.window = window.open('', 'bugger');
				Wounded.bugger.window.document.open();
				Wounded.bugger.window.document.write(
					'<style>.debug {clear: both;}'+
					'.debug div {margin: 5px;padding: 5px;}'+
					'.debug .name {float: left;}'+
					'.debug .val {float: left;}</style>'
				);
				if( Wounded.bugger.autoclose )
					Wounded.bugger.timer = true
			}
			if( Wounded.bugger.autoclose && Wounded.bugger.timer ){
				clearTimeout(Wounded.bugger.timer);
				Wounded.bugger.timer = setTimeout(function(){Wounded.bugger.window.document.close();}, 3000)
			}
			Wounded.bugger.window.document.write(
					'<div class="debug"><div class="name">'+name+'</div><div class="val">'+val+'</div></div>');
			return val;
		},
	propWriter: function(item){
			var list = []; for(var i in item){
				try{ list[list.length] = [i,item[i]]; }catch(e){ list[list.length] = [i, '{'+ e +'}']; } }
			var propwin = window.open('', 'propwindow');
			propwin.document.open();
			propwin.document.write('<html><head><title>Wounded JavaScript PropWriter</title>' +
				'<script type="text/javascript" src="http://magnificent-tears.com/wounded.js"></script>' +
				'</head><body><table>' +
				Wounded.map(list.sort(function(a,b){return (a[0] > b[0] ? 1 : -1);}),
					function(prop, index){ return '<tr bgcolor="' + (index % 2? '#dddddd' : '#eeeeee') + '"><td>' +
						'<a href="javascript:Wounded.propWriter(window.woundedprop.'+ prop[0] +');">' +
						prop[0].toString() + '</a></td><td><xmp>' + prop[1] + '</xmp></td></tr>'; }).join('\n')+'</table></body></html>');
			propwin.document.close();
			propwin.woundedprop = item;
			propwin.focus();
		},
/*
	useragent: function(){
			Wounded.map(arguments), function(agent){ var browser = agent.toLowerCase();
				switch(browser){
				case: 'opera': 	return (window.opera ? true : false); break;
				default: 		return (navigator.userAgent.toLowerCase().indexOf(browser) != -1); break;
				}
			}
		}
*/
	//alert: window.alert // I kept ending up with Wounded.alert so i figured what the hell
	alert: function(s){ void window.alert(s); } // I kept ending up with Wounded.alert so i figured what the hell
};
if( window.XMLHttpRequest ){ Wounded.xmlHttp = XMLHttpRequest; }// please, please, please...
else{if( window.ActiveXObject ){ // d'oh!
	try{ Wounded.xmlHttp = Wounded.bind(ActiveXObject, 'Msxml2.XMLHTTP'   ); }catch(e){ 
	try{ Wounded.xmlHttp = Wounded.bind(ActiveXObject, 'Microsoft.XMLHTTP'); }catch(e){ }} }}

if( overwrite ){
	Wounded.map(overwrite.onloads, function(over){ Wounded.add_onload(over); });
}
/*
Object.prototype.slice = function(start, end){ var j = -1, arr = [];
		for(var i=start; i<(end||this.length); ++i){ arr[++j] = this[i]; } return arr; }
*/

// no prototype?
if(typeof($) == 'undefined') var $ = Wounded.$;

//wtf?
function parseXML(node){
	var xmlStr = [];
	if(node.hasChildNodes && node.childNodes[0].nodeType!=3){
		return Wounded.map(node.childNodes, parseXML);
	}else{
		return "name = "+ node.nodeName +", value = "+ node.childNodes[0].nodeValue +"<br/>";
	}
}

/* // events
	if (window.addEventListener)
		window.addEventListener("load", func, false)
	else if (window.attachEvent)
		window.attachEvent("onload", func)
	else if (document.getElementById)
		window.onload=func
*/

/*
// exchange two visible elements: hide_and_show(id, id); hide_and_show(id, id, false);
function hide_and_show(e_hide, e_show){
	cancel_current_effects();
	Element.hide(e_hide);
	Element.show(e_show);
	//return (arguments.length > 1 && arguments[2] != undefined ? arguments[2] : true);
	return defined_or(arguments[2], true);
}

// wrapper for above
function show_and_hide(){ return hide_and_show(arguments[1], arguments[0], arguments[2]); }

// swap the display:noneness of two elements
function exchange_visibility(elm1, elm2){
	if( $(elm1).style.display != 'none' )
		return hide_and_show(elm1, elm2);
	else
		return hide_and_show(elm2, elm1);
}
*/
