var nlmScripter = window.nlmScripter = function(selector) {
	// If the context is a namespace object, return a new object
	return this instanceof nlmScripter ?
		this.init(selector) : new nlmScripter(selector);
};

window.$ = nlmScripter;

// Extend nlmScripter
nlmScripter.prototype = {
	init: function(element) {
		// Allow the user to use the T function without initializing the class.
		window.T = this.T;
		
		// Update this to handle IE/Opera
		if ( document.getElementById ) {
			if ( '' != element ) {
				var e = document.getElementById(element);
				this[0] = e;
				return this;
			}
		}
	},
	
	T: function() {
		var a = arguments;
		
		// An array of elements to be returned
		// e = element
		// s = plural
		var es = new Array();
		
		if ( 0 == a.length ) {
			alert('no arguments!');
		} else {
			var i = 0;
			var j = 0;
			
			for ( i=0; i<a.length; i++ ) {
				var e_undef = 1;
				if ( 'undefined' == typeof es[j] ) {
					e_undef = 0;
				}
			
				switch ( typeof a[i] ) {
					case 'string': {
						// See if it's an element
						// If not, make it a text node
						
						// Assume it's an element for now
						es[j] = document.createElement(a[i]);
						//es[j] = document.createTextNode(a[i]);
						
						break;
					}
					
					case 'object': {
						for ( var b in a[i] ) {
							// If b is 'next', then
							// create a new node
							// If b is 'content', then
							// create a new text node
							// If b is anything else,
							// make it an attribute and set it's value
							
							// Fix this bug: if no element is created
							// as a part of es[j] above in the string switch
							// then es[j] needs to be defined so that elements
							// can be appended to it.
							if ( 'undefined' == typeof es[j] ) {
								
								//es[j] = this[0];
							}
							
							switch ( b ) {
								// We're appending an element next
								case 'next': {
									var sub_e = a[i][b];

									for ( var k = 0; k<sub_e.length; k++ ) {
										if ( sub_e[k].length > 0 ) {
											for ( var n=0; n<sub_e[k].length; n++ ) {
												es[j].appendChild(sub_e[k][n]);
											}
										} else {
											es[j].appendChild(sub_e[k]);
										}
										
									}
									break;
								}
								
								case 'content': {
									var temp_text = document.createTextNode(a[i][b]);
									
									if ( 0 == e_undef ) {
										es[j] = temp_text;
									} else {
										es[j].appendChild(temp_text);
									}
									
									break;
								}
								
								default: {
									
									es[j].setAttribute(b, a[i][b]);
								}
							}
						}
						
						// Only update the current element after
						// we're done giving it attributes and sub
						// elements
						j++;

						break;
					}
				}
			}
		}

		return es;
	},

	append: function(es) {
		if ( undefined == es.length ) {
			es = new Array(es);
		}
		
		for ( i=0; i<es.length; i++ ) {
			this[0].appendChild(es[i]);
		}
	},
	
	replace: function(es) {
		this.removeChildren();
		this.append(es);
	},

	removeChildren: function() {
		while ( true == this[0].hasChildNodes() ) {
			this[0].removeChild( this[0].lastChild );
		}
	},

	addClass: function(class_name) {
		this[0].className = class_name;
	},
	
	value: function() {
		return this[0].value;
	},
	
	style: function(property, value) {
		if ( typeof property == 'object' ) {
			for ( p in property ) {
				this[0].style[p] = property[p];
			}
		} else {
			this[0].style[property] = value;
		}
	},
	
	attr: function(p, v) {
		this[0].setAttribute(p, v);
	},
	
	setValue: function(v) {
		this[0].value = v;
	},
	
	addHtml: function(code) {
		this[0].innerHTML = code;
	},
	
	children: function(node) {
		var cs = new Object();
		var children = this[0].getElementsByTagName(node);
		if ( children.length > 0 ) {
			
			var i=0;
			for ( i=0; i<children.length; i++ ) {
				cs[children[i].name] = children[i].value;
			}
		}
		
		return cs;
	},
	
	childrenRaw: function(node) {
		return this[0].getElementsByTagName(node);
	},
	
	json: function(js) {
		return eval("(" + js + ")");
	},

	// p for properties
	httpRequest: function(p) {
		var xmlHttp = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
		
		if ( !xmlHttp ) { alert('Failed to init ajax, logging error'); }
		
		// Set default variables if none are defined
		if ( 'undefined' == typeof p.isasync ) p.isasync = true;
		if ( 'undefined' == typeof p.isxml ) p.isxml = true;
		
		xmlHttp.open(p.method, p.url, p.isasync);

		// Set the headers
		var urlencoded = 0;
		if ( 'object' == typeof p.headers ) {
			for ( header in p.headers ) {
				xmlHttp.setRequestHeader(header, p.headers[header]);
				
				if ( header.indexOf('Content-type') != -1 && p.headers[header].indexOf('urlencoded') != -1 ) {
					urlencoded = 1;
				}
			}
		}
		
		// Send the text as urlencoded if the header isn't specified
		if ( 0 == urlencoded ) {
			xmlHttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
		}

		// Set the parameters if there are any
		if ( 'object' == typeof p.params ) {
			var params = '';
			
			var x = 0;
			var sep = '';
			for ( param in p.params ) {
				sep = '&';
				if ( x == 0 ) { sep = '' ; x++; }
				
				params += sep + encodeURIComponent(param) + '=' + encodeURIComponent(p.params[param]);
			}
		}

		stateChange = function() {
			if ( ( xmlHttp.readyState == 4 ) && ( xmlHttp.status == 200 ) ) {
				var xmlDoc = ( true == p.isxml ? xmlHttp.responseXML.documentElement : xmlHttp.responseText );
				p.callback(xmlDoc);
			}
		}
		
		if ( true == p.isasync ) {
			xmlHttp.onreadystatechange = stateChange;
		} else {
			// Just call the callback
			stateChange();
		}
		
		xmlHttp.send(params);
	},
	
	httpCreateParams: function(callback) {
		// callback is a custom function that 
		// creates params based on whatever it wants to do
		// it should return an object list
		return callback();
	}
};