/* radiac's library
** Purpose: Basic supporting library functions
** Date: 2006-05-12
** Version: 0.1 alpha - not intended for public release.
** Latest version: see radiac.net
*/



getO = function(o) {
	if (typeof o == 'string') return document.getElementById(o);
	return o;
}

// DOM page 83, see http://www.quirksmode.org/js/findpos.html
findPosX = function(o) {
	var x = 0;
	if (o.offsetParent) {
		do {
			x += o.offsetLeft;
		} while (o = o.offsetParent);
	} else if (o.x) {
		x = o.x;
	}
	return x;
}
findPosY = function(o) {
	var y = 0;
	if (o.offsetParent) {
		do {
			y += o.offsetTop;
		} while (o = o.offsetParent);
	} else if (o.y) {
		y = o.y;
	}
	return y;
}

// Copy the values from object2 into object1
objectSplice = function(o1, o2) {
	for (var p in o2) {
		o1[p] = o2[p];
	}
}


Vector = function(x, y) {
	return {x:x,y:y};
}

function getStyle(e,p) {
	if (e.currentStyle) return e.currentStyle[p];
	if (window.getComputedStyle) return document.defaultView.getComputedStyle(e,null).getPropertyValue(p);
	return NaN;
}
function getStyleInt(e,p) {
	return parseInt(getStyle(e,p));
}



/* DOME
** DOM Element management

There are no specific functions to bind elements to nodes; that code is trivial and makes no sense to be abstracted.
*/

// DOME
// This simply provides functions for DOM Element management, and should not be instantitated
DOME = {
	// Node Type for a text node - guaranteed value for Node.TEXT_NODE
	text: 3,
	
	// DOME.create(type, options)
	// Create a new element and copy options into it
	// Arguments:	type		[String]	Type of new element to create (ie 'DIV')
	//		options		[Object]	Optional: each property will become a property of the new element
	//						Special case: style:{...} properties will be copied into element.style[..]
	// Returns:	element		[HTMLElement]	New element
	create: function(type, options) {
		// Create node
		var element = document.createElement(type);
		
		// Copy options into new element
		for (var property in options) {
			if (property == 'style') {
				objectSplice(element[property], options[property]);

			} else {
				element[property] = options[property];
			}
		}
		
		// Return the finished element
		return element;
	},
	
	// DOME.setText(element, text)
	// Set a new value for an existing text node, or create one if missing
	// Arguments:	element		[HTMLElement]	The element to set the text on. If it is a text node, or if the element.lastChild is a text node, the existing text node will be changed, otherwise a new text node will be added.
	//		text		[String]	The text to set
	//		append		[Boolean]	Optional: If true, append to any existing text nodes
	// Returns:	element		[HTMLElement]	The same element that was passed in
	setText: function(element, text, append) {
		// First try to append to existing text nodes
		if (element.nodeType == DOME.text) {
			element.nodeValue = (append) ? element.nodeValue + text : text;
		} else if (element.lastChild && element.lastChild.nodeType == DOME.text) {
			element.lastChild.nodeValue = (append) ? element.lastChild.nodeValue + text : text;
			
		// Otherwise create and append a text node to the element
		} else {
			element.appendChild(document.createTextNode(text));
		}
		return element;
	},
	
	// DOME.createComplex(complexNode)
	// Create a complex DOM element (ie a popin body) from a single internal structure, to simplify creation
	// Arguments:	complexNode	[Array|String]	A node conforming to the createComplex node structure; either an array or a text string
	// Returns:	element		[HTMLElement]	A new HTML element that contains the new DOM structure	
	createComplex: function(complexNode) {
		// Deal with single string node
		if (typeof complexNode == 'string') return document.createTextNode(complexNode);
		
		// Create root node
		var doneStack = [ DOME.create(complexNode[0], complexNode[1]) ];
		var group = complexNode[2];
		var remainStack = new Array();
		
		// Loop through children
		while (group) {
			// Look at next
			var current = group.shift();
			
			// Create node
			if (typeof current == 'string') {
				DOME.setText(doneStack[doneStack.length-1], current, true);
			} else {
				// Append new node to top node of done
				node = DOME.create(current[0], current[1]);
				doneStack[doneStack.length-1].appendChild(node);
			
				// If there is a child, stack and run with child
				if (current[2]) {
					remainStack.push(group);
					group = current[2];
					doneStack.push(node);
				}
			}
			
			// If no nodes left in the current group, destack
			while (group && group.length == 0) {
				// Next group off the top of the stack
				group = remainStack.pop();
				
				// Drop node from the top of the doneStack - already child of another
				if (group) doneStack.length--;
			}
		}
		
		return doneStack[0];
	},
	
	// DOME.delete(DOME)
	// ++
	
	// DOME.loadCSS(url)
	// Load a CSS file
	// Arguments:	url		[String]	URL for the CSS file to load
	loadCSS: function(url) {
		// Create node
		var style = DOME.create('script', {type:'text/css'});
		DOME.addText(style, '@import "'+url+'"');
		
		// Append to body
		document.body.appendChild(style);
	},
	
	// DOME.loadScript(url)
	// Load a JavaScript file
	// Arguments:	url		[String]	URL for the JavaScript file to load
	loadScript: function(url) {
		// Create node
		var script = DOME.create('script', {type:'text/javascript', src:url});
		
		// Append to body
		document.body.appendChild(script);
	}
}

