function clearElement( e )
{
	while ( e.firstChild )
	{
		e.removeChild(e.firstChild);
	}
}



/**
	Helper function to create DOM elements.

	type: tag.class#name (or tag#name.class)
	properties: {attr1:'val1',attr2:'val2',style:{css1:'val1',...},style:'ccs1:val1;...',...}
/**/
function DOMElement( type, properties ) {
	var matches = type.match(/(^\w+)([\.#]\w+)?([\.#]\w+)?/);

	if ( !matches ) {
		return DOM(
			[['div',
				{style:{
					backgroundColor: 'white',
					color: 'red',
					display: 'inline',
					fontSize: '1.5em',
					padding:'0.5em',
					position:'relative'
				}},
				'malformed DOMElement(...) call']]
		);
	}

	var element = document.createElement(matches[1]);

	for ( var i = 2; i < 4; ++i ) {
		if ( matches[i] ) {
			switch ( matches[i].substr(0,1) ) {
				case '.':
					element.setAttribute('class',matches[i].substr(1));
					element.className = matches[i].substr(1);
					break;
				case '#':
					element.setAttribute('id',matches[i].substr(1));
					element.setAttribute('name',matches[i].substr(1));
					break;
				default:
					break;
			}
		} else {
			break;
		}
	}

	if ( !properties ) {
		return element;
	}

	for ( var attribute in properties ) {
		if ( attribute.toLowerCase() == 'style' ) {
			if ( properties[attribute].charAt ) {
				var style_match = /([\w\-]+)\:([^;]+)/g;

				while ( true ) {
					var style_matches = style_match.exec(properties[attribute]);
					if ( !style_matches || style_matches.length < 3 ) {
						break;
					}

					element.style[style_matches[1]] = style_matches[2];
				}
			
				continue;
			} else {
				for ( var style_attribute in properties[attribute] ) {
					element.style[style_attribute] = properties[attribute][style_attribute];
				}
			}
		} else if ( attribute.substr(0,2).toLowerCase() == 'on' ) {
			element[attribute] = properties[attribute];
		} else {
			element.setAttribute(attribute,properties[attribute]);
		}
	}

	return element;
}



function DOMGetSize( element )
{
	if ( !element )
	{
		return null;
	}

	var element_dimensions = {
		height:   element.offsetHeight,
		left:     0,
		top:      0,
		width:    element.offsetWidth
	};

	var element_parent = element;
	while ( element_parent )
	{
		element_dimensions.left += element_parent.offsetLeft;
		element_dimensions.top  += element_parent.offsetTop;

		element_parent = element_parent.offsetParent;
	}

	return element_dimensions;
}



/**
	Pass a structure as (OPT arguments are optional):
	[
		[
			'element_type.class_name#name_id',
			OPT {
				attr1:'val1',
				attr2:'val2',
				OPT style:{
					cssprop1:'val1',
					...
				},
				OPT style:'cssprop1:val1;...',
				...
			},
			[child_nodes] OR 'element_text'
		],
		...
	]

	**NOTE**
	This will return the created DOM structure, BUT... if you pass the object you'd like to insert into as
	the second (optional) parameter, it'll insert itself. This is advisable for multiple top-level children,
	as otherwise there'll be an extra div thrown around all of them.

	**NOTE**
	In attribute declarations, style may be passed as an object or as a string -- should set identically
	in either case. The option is there depending on how you like your code formatted.

	**NOTE**
	Similarly, the third declaration is the child node(s) to insert. If a pure string is discovered, it is
	converted to a text node and inserted. Otherwise, a recursive DOM structure is generated and inserted.

	**RETURN**
	Returns a DOM-equivalent element. If multiple top-level children are passed, wraps them in a div (exception:
	see first **NOTE**). Does *no* error-checking (yet), so play nice :)
/**/
function DOM( elements, parent_element ) {
	if ( elements.length == 1 ) {
		var element = DOMElement(elements[0][0],elements[0][1]);

		if ( elements[0][2] ) {
			if ( elements[0][2].charAt ) {
				if ( /^input\b/.exec(elements[0][0].toLowerCase()) ) {
					element.setAttribute('value',elements[0][2]);
				} else {
					element.appendChild(document.createTextNode(elements[0][2]));
				}
			} else {
				DOM(elements[0][2],element);
			}
		}

		if ( parent_element ) {
			parent_element.appendChild(element);
		} else {
			parent_element = element;
		}
	} else {
		if ( !parent_element ) {
			parent_element = DOMElement('div');
		}

		for ( var i = 0; i < elements.length; ++i ) {
			var element = DOMElement(elements[i][0],elements[i][1]);

			if ( !elements[i][2] || elements[i][2].charAt )
			{
				var tag   = elements[i][0].toLowerCase();
				var value = elements[i][2] == null ? '' : elements[i][2];
				if ( /^input\b/.exec(tag) )
				{
					element.setAttribute('value',value);
				}
				else if ( tag == 'img' )
				{
					element.setAttribute('src',value);
				}
				else if ( tag != 'br' )
				{
					element.appendChild(document.createTextNode(value));
				}
			}
			else
			{
				DOM(elements[i][2],element);
			}

			parent_element.appendChild(element);
		}
	}

	return parent_element;
}

/**
	Here's some example usage of the DOM(...) function.
/**
var dom = document.getElementById('dom');
dom.appendChild(DOM(
	[
		[
			'div',
			{
				style: {
					backgroundColor: 'green',
					height: '100px',
					position: 'absolute',
					width: '400px'
				}
			},
			[
				[
					'a',
					{
						href: 'javascript:void(0);',
						style: {
							color: 'red',
							fontFamily: 'sans-serif',
							fontSize: '2em'
						},
						onclick: function( event ) {
							alert('clicked me!');
						}
					},
					'my test string'
				],
				[
					'input',
					{
						onclick: function( event ) {
							alert('clicked button!');
						},
						type: 'button'
					},
					'buttonage'
				]
			]
		]
	));
/**/

