var com, $pr, $or;

com.saltcollective.Phocus.DOM=function(){};
$pr=com.saltcollective.Phocus.DOM.prototype;
$or=com.saltcollective.Phocus.DOM;

// DOM properties
$pr.d=$or.d=document;
$pr.context=$or.context=document;
$pr.nodeint=$or.nodeint=0;
$pr.nodeid=$or.nodeid='__phocusnode';
$pr.nodecache=$or.nodecache={};

// node variable storage
$or.nodestorage={};

// methods
// getNode - tests for a string and returns a node
$pr.getnodes=$or.getnodes=function(query,c) // : Array
{
	var bits, tagName, className, id, element, found, foundCount, currentContextIndex, regexp, attrName, attrOperator, attrValue, checkFunction, h, i, j, k, t, ts, elements, rtn, currentContext, q, checkFunctiona, checkFunctionb, checkFunctionc, checkFunctiond, checkFunctione, checkFunctionf, checkFunctiong;
	
	q=this.getquerycontext()+query;
	currentContext = [document];
					
	checkFunctiona = function(e) { return (e.getAttribute(attrName) == attrValue); };
	checkFunctionb = function(e) { return (e.getAttribute(attrName) ? e.getAttribute(attrName).match(new RegExp('(\\s|^)'+attrValue+'(\\s|$)')) : false); };
	checkFunctionc = function(e) { return (e.getAttribute(attrName) ? e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?')) : false); };
	checkFunctiond = function(e) { return (e.getAttribute(attrName) ? e.getAttribute(attrName).indexOf(attrValue) === 0 : false); };
	checkFunctione = function(e) { return (e.getAttribute(attrName) ? e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length : false); };
	checkFunctionf = function(e) { return (e.getAttribute(attrName) ? e.getAttribute(attrName).indexOf(attrValue) > -1 : false); };
	checkFunctiong = function(e) { return e.getAttribute(attrName); };
		
	if(!c)
	{
		c=this.context;
	}
	try
	{
		if(typeof query == 'string')
		{ 				
			// Attempt to fail gracefully in lesser browsers
			if (!document.getElementsByTagName)
			{
				return new com.saltcollective.Phocus.DOM_nodeset();
			}
			// Split selector in to tokens
			ts = q.split(' ');
			for (i = 0; i < ts.length; i++)
			{
				t = ts[i].replace(/^\s+/,'').replace(/\s+$/,'');
				if (t.indexOf('#') > -1)
				{
					// Token is an ID selector
					bits = t.split('#');
					tagName = bits[0];
					id = bits[1];
					element = document.getElementById(id);
					if (tagName && element.nodeName.toLowerCase() != tagName)
					{
						// tag with that ID not found, return false
						currentContext = [];
						break;
					}
					// Set currentContext to contain just this element
					currentContext = [element];
					continue; // Skip to next token
				}
				if (t.indexOf('.') > -1)
				{
					// Token contains a class selector
					bits = t.split('.');
					tagName = bits[0];
					className = bits[1];
					if (!tagName)
					{
						tagName = '*';
					}
					// Get elements matching tag, filter them for class selector
					found = [];
					foundCount = 0;
					for (h = 0; h < currentContext.length; h++)
					{
						if (tagName == '*')
						{
							elements = this.getAllChildren(currentContext[h]);
						} else
						{
							elements = currentContext[h].getElementsByTagName(tagName);
						}
						for (j = 0; j < elements.length; j++)
						{
							found[foundCount++] = elements[j];
						}
					}
					currentContext = [];
					currentContextIndex = 0;
					regexp=new RegExp('(\\s|^)'+className+'(\\s|$)');
					for (k = 0; k < found.length; k++)
					{
// patch 1*							if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b')))
						if (found[k].className && found[k].className.match(regexp))
						{
							currentContext[currentContextIndex++] = found[k];
						}
					}
					continue; // Skip to next token
				}
				// Code to deal with attribute selectors
				if (t.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) //"
				{
					tagName = RegExp.$1;
					attrName = RegExp.$2;
					attrOperator = RegExp.$3;
					attrValue = RegExp.$4;
					if (!tagName)
					{
						tagName = '*';
					}
					// Grab all of the tagName elements within current context
					found = [];
					foundCount = 0;
					for (h = 0; h < currentContext.length; h++)
					{
						if (tagName == '*')
						{
							elements = this.getAllChildren(currentContext[h]);
						} else
						{
							elements = currentContext[h].getElementsByTagName(tagName);
						}
						for (j = 0; j < elements.length; j++)
						{
							found[foundCount++] = elements[j];
						}
					}
					currentContext = [];
					currentContextIndex = 0;
							
					switch (attrOperator)
					{
						case '=': // Equality
							checkFunction = checkFunctiona;
							break;
						case '~': // Match one of space seperated words 
// patch 1*								checkFunction = function(e) { return (e.getAttribute(attrName) ? e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b')) : false); };
							checkFunction = checkFunctionb;
							break;
						case '|': // Match start with value followed by optional hyphen
							checkFunction = checkFunctionc;
							break;
						case '^': // Match starts with value
							checkFunction = checkFunctiond;
							break;
						case '$': // Match ends with value - fails with "Warning" in Opera 7
							checkFunction = checkFunctione;
							break;
						case '*': // Match ends with value
							checkFunction = checkFunctionf;
							break;
						default :
							// Just test for existence of attribute
							checkFunction = checkFunctiong;
					}
					currentContext = [];
					currentContextIndex = 0;
					for (k = 0; k < found.length; k++)
					{
						if (checkFunction(found[k]))
						{
							currentContext[currentContextIndex++] = found[k];
						}
					}
					// alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);
					continue; // Skip to next token
				}
				// If we get here, token is JUST an element (not a class or ID selector)
				tagName = t;
				found = [];
				foundCount = 0;
				for (h = 0; h < currentContext.length; h++)
				{
					elements = currentContext[h].getElementsByTagName(tagName);
					for (j = 0; j < elements.length; j++)
					{
						found[foundCount++] = elements[j];
					}
				}
				currentContext = found;
			}
		} else if (query.length) // if this is an array
		{
			currentContext = query;
		} else if(typeof query == 'object')
		{
			return phocus.DOM.getNode(query);
		} else
		{
			// error
			this.error='Wrong parameter passed as a node reference.';
			throw this.error;
		}
	} catch(err)
	{
		return err;
//			this.Catcher.log(err);
	}
	
	rtn=new com.saltcollective.Phocus.DOM_nodeset();
	rtn.parsearray(currentContext);
// removed because I don't want to have to error check this each time. Maybe error check length in DOM_nodes on any action
//	if(rtn.length == 0)
//		return null;
	return rtn;
};
// the basic query context
$pr.getquerycontext=$or.getquerycontext=function(){return '';};

$pr.getAllChildren=$or.getAllChildren=function(e)
{
	// Returns all children of element. Workaround required for IE5/Windows. Ugh.
	return e.all ? e.all : e.getElementsByTagName('*');
};

$pr.getETarget=$or.getETarget=function(e)
{
	var te=null; // target element
	if(typeof e.target != 'undefined')
	{
		te=e.target;
	} else
	{
		te=e.srcElement;
	}
	while(te.nodeType==3 && te.parentNode!== null)
	{
		te=te.parentNode;
	}
	return te;
};
$pr.stopEvent=$or.stopEvent=function(e)
{
	if(typeof e.stopPropagation != 'undefined')
	{
		e.stopPropagation();
	} else
	{
		e.cancelBubble = true;
	}
		
	// 20080102
	// This following block was commented out for some reason, if for 
	// some reason this function fails to work as expected in future, 
	// you have a good idea of why
	e.returnValue=false;
	if(typeof e.preventDefault != 'undefined')
	{
		e.preventDefault();
	}
};
$pr.getdims=$or.getdims=function()
{
	if(typeof window.innerWidth == 'number')
	{
		return new phocus.Point(window.innerWidth,window.innerHeight);
	} else if(document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight))
	{
		return new phocus.Point(document.documentElement.clientWidth,document.documentElement.clientHeight);
	}
};
$pr.getmousepos=$or.getmousepos=function(e,el)
{
	var rtn=new phocus.Point(0,0);
	var screenx=e.clientX;
	var screeny=e.clientY;
	var offset=this.getscrollpos();
	rtn.x=screenx+offset.x;
	rtn.y=screeny+offset.y;
	if(typeof el != 'undefined' && el.issub)
	{
		var elpos=el.getposition();
		rtn.x=rtn.x-elpos.x;
		rtn.y=rtn.y-elpos.y;
	}
	return rtn;
};
$pr.getscrollpos=$or.getscrollpos=function()
{
	var rtn=new phocus.Point(0,0);
	if(typeof window.pageYOffset != 'undefined')
	{
		rtn.x=window.pageXOffset;
		rtn.y=window.pageYOffset;
	} else if (typeof document.documentElement.scrollTop != 'undefined' && document.documentElement.scrollTop > 0)
	{
		rtn.x=document.documentElement.scrollLeft;
		rtn.y=document.documentElement.scrollTop;
	} else if(document.body.scrollTop != 'undefined')
	{
		rtn.x=document.body.scrollLeft;
		rtn.y=document.body.scrollTop;
	}
	return rtn;
};
$pr.getNode=$or.getNode=function(node)
{
	var nid='';
	if(node.id)
	{
		nid=node.id;
	} else
	{
		nid=com.saltcollective.Phocus.DOM.nodeid+(com.saltcollective.Phocus.DOM.nodeint++);
	}
	
	var comopt=com.saltcollective.Phocus.DOM.nodecache;
	
	if(comopt[nid] && comopt[nid].context && comopt[nid].context.nodeType == 1)
	{
		return com.saltcollective.Phocus.DOM.nodecache[nid];
	}
	
	var phocusnode=new com.saltcollective.Phocus.DOM_node(node);
	phocusnode.set('id',nid);
	com.saltcollective.Phocus.DOM.nodecache[nid]=phocusnode;
	
	return phocusnode;
};
$pr.deleteNode=$or.deleteNode=function(node)
{
	var nid='';
	if(node.id)
	{
		nid=node.id;
	} else
	{
		return false;
	}
	
	if(com.saltcollective.Phocus.DOM.nodecache[nid])
	{
		com.saltcollective.Phocus.DOM.nodecache[nid]=null;
		delete com.saltcollective.Phocus.DOM.nodecache[nid];
		return true;
	}
	return false;
};
$pr.cleanupcache=function()
{
	var cache=com.saltcollective.Phocus.DOM.nodecache;
	for(var i in cache)
	{
		if(cache[i].get('id') != i)
		{
			cache[i]=null;
			delete cache[i];
		}
	}
};
$pr.flush=$or.flush=function()
{
//		com.saltcollective.Phocus.DOM.nodeint=0;
//
//		removed this because we want IDs to be unique.
//		If we wanted to be REALLY good at this point
//		we would loop through and remove any IDs that
//		we could match as a phocus_NODE ID.
	for(var i in com.saltcollective.Phocus.DOM.nodecache)
	{
		if(com.saltcollective.Phocus.DOM.nodecache.hasOwnProperty(i))
		{
			var op=com.saltcollective.Phocus.DOM.nodecache[i];
			if(op.get('id').indexOf(this.nodeid)===0)
			{
				op.set('id','');
			}
			op=null;
		}
	}

	com.saltcollective.Phocus.DOM.nodecache={};
};
// DOM READY listener and function
//$pr.onDOMReady = 
$or.onDOMReady = function(){};
//$pr.DOMReady = 
$or.DOMReady = false;
if (document.addEventListener)
{
	document.addEventListener("DOMContentLoaded", function(){phocus.DOM.DOMReady=true; phocus.DOM.onDOMReady();}, false);
} else if (document.all && !window.opera)
{
	document.write('<script type="text/javascript" id="contentloadtag" defer="defer" src="javascript:void(0)"><\/script>');
	var contentloadtag=document.getElementById("contentloadtag");
	contentloadtag.onreadystatechange=function()
	{
		if (this.readyState=="complete")
		{
			phocus.DOM.DOMReady=true;
			phocus.DOM.onDOMReady();
		}
	};
}
var oldonloadDOM=window.onload;
window.onload=function()
{
	if(typeof oldonloadDOM == 'function')
	{
		oldonloadDOM();
	}
	if(!phocus.DOM.DOMReady)
	{
		phocus.DOM.onDOMReady();
		phocus.DOM.DOMReady=true;
	}
};

com.saltcollective.Phocus.register(com.saltcollective.Phocus.DOM,'DOM');

com.saltcollective.Phocus.DOM_node=function(node)
{
	this.context=node;
//	this.context.phocusNode=this;
	this.style=node.style;
};
com.saltcollective.Phocus.DOM_node.prototype=com.saltcollective.Phocus.extend(com.saltcollective.Phocus.DOM);
$pr=com.saltcollective.Phocus.DOM_node.prototype;
$pr.d=document;
$pr.issub=true;
$pr.locked=false;

// query context - for extending subqueries.
$pr.getquerycontext=function()
{
	return this.context.nodeName.toLowerCase()+'#'+this.get('id')+' ';
};
/* lock and unlock */
$pr.lock=function()
{
	this.locked=true;
};
$pr.unlock=function()
{
	this.locked=false;
};
// add / remove class
$pr.addclass=function(cn)
{
	if(typeof cn != 'string') { return; }

	var cls=this.get('className').split(' ');
	for(var i=cls.length-1;i>=0;i--)
	{
		if(cls[i] == cn) { return; }
	}
		
	cls.push(cn);
	
	this.set('className',cls.join(' '));
};
$pr.delclass=function(cn)
{
	if(typeof cn != 'string') { return; }

	var cls=this.get('className').split(' ');
	for(var i=cls.length-1;i>=0;i--)
	{
		if(cls[i] == cn)
		{
			cls.splice(i,1);
		}
	}
			
	this.set('className',cls.join(' '));
	
};
/* properties take the following form:

	alias : map [, unit [, rounding]]
	if map is p:X, that refers to a parent property (where X is the property name to which it refers)
	if map is an empty string: '' then the name of the property is also the name of the style property
	if map is b:X, that refers to a base property
*/
$pr.properties=
{
	width:				['','px', true],
	height:				['','px', true],
	top:				['','px', true],
	right:				['','px', true],
	bottom:				['','px', true],
	left:				['','px', true],
	margin:				['','px', true],
	marginTop:			['','px', true],
	marginRight:		['','px', true],
	marginBottom:		['','px', true],
	marginLeft:			['','px', true],
	padding:			['','px', true],
	paddingTop:			['','px', true],
	paddingRight:		['','px', true],
	paddingBottom:		['','px', true],
	paddingLeft:		['','px', true],
	borderWidth:		['','px', true],
	borderTopWidth:		['','px', true],
	borderRightWidth:	['','px', true],
	borderBottomWidth:	['','px', true],
	borderLeftWidth:	['','px', true],
	fontSize:			['','px', true],
	w:					['p:width'],
	h:					['p:height'],
	t:					['p:top'],
	r:					['p:right'],
	b:					['p:bottom'],
	l:					['p:left'],
	z:					['p:zIndex'],
	x:					['p:left'],
	y:					['p:top'],
	bg:					['background'],
	color:				['f:colour'],
	colour:				['f:colour'],
	backgroundColor:	['f:bgColour'],
	bgColour:			['f:bgColour'],
	bgColor:			['f:bgColour'],
// Ive removed these because the rounding was fucking up the colour properties when passing a string hex value.
// can't quite remember why I was rounding the values. If anything goes wrong with colour, look here first.
//	color:				['f:colour',0,1],
//	backgroundColor:	['f:bgColour',0,1],
//	bgColour:			['f:bgColour',0,1],
//	bgColor:			['f:bgColour',0,1],
	complete:			['b:complete'],
	id:					['b:id'],
	className:			['b:className'],
	title:				['b:title'],
	alt:				['b:alt'],
	name:				['b:name'],
	value:				['b:value'],
	action:				['b:action'],
	type:				['b:type'],
	src:				['b:src'],
	target:				['b:target'],
	nodeName:			['b:nodeName'],
	nodeType:			['b:nodeType'],
//	class:				['p:className'], // class is a reserved word - LE
	href:				['b:href'],
	rev:				['b:rev'],
	rel:				['b:rel'],
	src:				['b:src'],
	innerHTML:			['f:innerHTML'],
	opacity:			['f:alpha'],
	alpha:				['f:alpha'],
	dims:				['f:dims'],
	pos:				['f:position'],
	scroll:				['f:scroll'],
	parent:				['f:parent']
};
// to String
$pr.toString=function(){ return 'DOM '+this.context.nodeName+(this.context.id ? ': '+this.context.id : ''); };
// set a style property
$pr.set=function(prop,value,override)
{
	var context, p, u, v, propsp, opt;

	if(this.locked) { return false; }

	// style is the default context as it contains the most properties that one would want changed
	context='style';

	p=this.properties[prop];
	
	p=this.getprop(prop);
	u=p[1] && p[1][1] ? p[1][1] : '';
	v=p[1] && p[1][2] ? Math.round(value) : value;
	prop=p[1] && p[1][0] ? p[1][0] : p && p[0] ? p[0] : prop;
		
	propsp=prop.split(':');
	if(propsp.length > 1)
	{
		prop=propsp[1];
		context=propsp[0];
	}
	
	if(typeof value == 'string' && value=='auto')
	{
		opt='auto';
	} else if(typeof value == 'string' && value==='')
	{
		opt='';
	} else
	{
		opt=(typeof v == 'string' && v==='') ? '' : (!u || typeof u == 'undefined') ? v : v+u;
	}
	
	if(context == 'style' || override=='style')
	{
		this.style[prop]=opt;
		if(opt == '')
		{
			delete this.style[prop];
		}
	} else if(context == 'b' || override=='attribute')
	{
		this.context[prop]=opt;
	} else if(context == 'f')
	{
		this['set'+prop](opt);
	}
};
// get a style property
$pr.get=function(prop)
{
	var context,p,u,propsp,rtn;

	// style is the default context as it contains the most properties that one would want changed
	context='style';

	p=this.properties[prop];
	
	p=this.getprop(prop);
	u=p[1] && p[1][1] ? p[1][1] : '';
	prop=p[1] && p[1][0] ? p[1][0] : p && p[0] ? p[0] : prop;
	
	propsp=prop.split(':');
	if(propsp[1])
	{
		prop=propsp[1];
		context=propsp[0];
	}
	
//	alert(this.context == window);
	if(context == 'style')
	{
		rtn = this.style[prop];
	} else if(context == 'b')
	{
		rtn = this.context[prop];
	} else if(context == 'f')
	{
		rtn = this['get'+prop]();
	}
		
	if(u!=='')
	{
		rtn=rtn.split(u).join('').split(' ')[0];
	}
	
	return rtn;
};
$pr.setvar=function(prop,value)
{
	var id=this.get('id');
	
	if(typeof phocus.DOM.nodestorage[id] != 'object' || phocus.DOM.nodestorage[id] === null)
	{
		phocus.DOM.nodestorage[id] = {};
	}
		
	phocus.DOM.nodestorage[id][prop] = value;
};
$pr.getvar=function(prop)
{
	var id=this.get('id');
	
	if(typeof phocus.DOM.nodestorage[id] != 'object' || phocus.DOM.nodestorage[id] === null || typeof phocus.DOM.nodestorage[id][prop] == 'undefined')
	{
		return null;
	}
	
	return phocus.DOM.nodestorage[id][prop];
};
// private 
// getprop recursively loops through and gets the final property
$pr.getprop=function(prop)
{
	var p=this.properties[prop];
	var propsp,rtn;
	
	if(!p)
	{
		return [prop,null,true];
	} else if(p && !isNaN(p.length))
	{
		propsp=p[0].split('p:');
	}
		
	// update 20080207-01
	if(propsp[1])
	{
		rtn=this.getprop(propsp[1]);
	}
	
	if(rtn && rtn[2]===true)
	{
		return rtn;
	} else if(!rtn || !rtn[1])
	{
		rtn=[prop,p];
	}
	
	return rtn;
};
// add node. Multi purpose node addition.
// e:string[, m:string[, a:array[, t:text[, c:node[, n:number]]]]]
// e - the element to add
// m - mode. This determines where the node[s] are attached. legal values: BEFORE, AFTER, REPLACE, REPLACECHILDREN, BEGINNING, END (default: END)
// a - attributes : array of objects - [{p:property;v:variable},{p:property;v:variable}]
// EDIT: changed above to {property1:value1, property2:value2 ... propertyN:valueN}
// t - text
// n - number. Will add the node 'n' number of times
$pr.addnode=function(e,m,a,t,n)
{
	var rtn, cn, _n;

	if(typeof e.name != 'undefined' && e.name == 'DOM_nodeset')
	{
		rtn=new com.saltcollective.Phocus.DOM_nodeset();
		for(var i=0;i<e.length;i++)
		{
			rtn.join(this.addnode(e.node(i),m,a,t,n));
		}
		
		return rtn;
	}

	cn=this.context;
	rtn=new com.saltcollective.Phocus.DOM_nodeset();

	// verifying method properties
	if(!m || m===undefined) { m='END'; }
	if(!n || n===undefined) { n=1; }
	if(!a || a===undefined) { a=[]; }
	if(!t || t===undefined) { t=''; }
			
	// cleaning out any potential duplicate IDs
	var rid=function(n)
	{
		if(typeof n == 'object' && n !== null && typeof n.childNodes == 'object')
		{
			for(var k=n.childNodes.length-1;k>=0;k--)
			{
				var c=n.childNodes[k];
				if(typeof c == 'object' && c !== null) { rid(c); }
			}
		}
		if(typeof n == 'object' && n !== null && typeof n.id != 'undefined') { n.id=''; }
	};
	for(var j=0;j<n;j++)
	{
		if(typeof e == 'string')
		{
			_n=this.d.createElement(e);
		} else
		{
			if(typeof e.issub != 'undefined' && e.issub)
			{
				e=e.context;
			}
			_n=e.cloneNode(true);
			rid(_n);
		}
		
		switch(m)
		{
			case 'BEFORE':
				_n=cn.parentNode.insertBefore(_n,cn);
				break;
			case 'AFTER':
				_n=cn.parentNode.insertBefore(_n,cn.nextSibling);
				break;
			case 'REPLACE':
				cn.parentNode.replaceChild(_n,cn);
				break;
			case 'BEGINNING':
				_n=cn.insertBefore(_n,cn.firstChild);
				break;
			case 'REPLACECHILDREN':
				this.clear();
				_n=cn.appendChild(_n);
				break;
			default:
				_n=cn.appendChild(_n);
		}
		_n=com.saltcollective.Phocus.DOM.getNode(_n);
		_n.createdby='DOM_nodeset';
		for(var k in a)
		{
			if(a.hasOwnProperty(k))
			{
				_n.set(k,a[k]);
			}
		}
		if(t!=='')
		{
			_n.context.appendChild(this.d.createTextNode(t));
		}
		rtn.addelement(_n.context);
	}
	return rtn;
};
$pr.deletenode=function()
{
	var cn=this.context;
	cn.parentNode.removeChild(cn);
	phocus.DOM.deleteNode(cn);
	this.context=null;
};

// clone
$pr.getcopy=function()
{
	var copy=this.context.cloneNode(true);
	copy.id='';
	return phocus.DOM.getNode(copy);
};

// previous sibling
$pr.previous=function()
{
	var n = this.context;
	do
	{
		n = n.previousSibling;
	} while (n && n.nodeType != 1);
	
	if(!n) { return null; }
	return new phocus.DOM_node(n);
};
$pr.moveup=function()
{
	var p=this.previous();
	if(!p) { return; }
	
	var c=this.context.cloneNode(true);
	this.deletenode();
	
	p.addnode(c,'BEFORE');
};

// next sibling
$pr.next=function()
{
	var n = this.context;
	do
	{
		n = n.nextSibling;
	} while (n && n.nodeType != 1);
	
	if(!n) { return null; }
	return new phocus.DOM_node(n);
};
$pr.movedown=function()
{
	var p=this.next();
	if(!p) { return; }
	
	var c=this.context.cloneNode(true);
	this.deletenode();
	
	p.addnode(c,'AFTER');
};


// add event
// e:string, m:method[, cap:node=false]
// e    - the event to add
// m    - The method to add
// cap  - Whether the event is applied during capture or bubble
$pr.setevent=function(e,m,cap)
{
	var cn=this.context;

	if(!cap) { cap=false; }
	ae='attachEvent'; // ie
	ael='addEventListener'; // everything else
	if(typeof cn[ael] != 'undefined')
	{
		cn[ael](e,m,cap);
	} else if(typeof cn[ae] != 'undefined')
	{
		var fs=e+m;
		cn['e'+fs]=m;
		cn[fs]=function(e)
		{
			if(typeof e == "undefined")
			{
				e=window.event;
			}
			cn['e'+fs](e);
		};
		
		cn[ae]('on'+e,cn[fs]);
	}
	else
	{
		// memory leak city (fortunately only in older browsers)
    	var et='on'+e; // event type
    	var te=cn[et];// target event
    	if(typeof te == 'function')
    	{
    		var ol=te; // old listener
    		te=function()
    		{
    			ol();
    			return m();
    		};
    	} else
    	{
			te=m;
    	}
    }
    
	return [e,m,cap];
};
$pr.unsetevent=function(e,m,cap)
{
	var cn=this.context;
	
	// error checking a parsed array and making an assumption of it's validity based on a number of arbitrary tests.
	if(typeof e == 'object' && e.length==3 && typeof e[0] == 'string' && typeof e[1] == 'function' && typeof e[2]=='boolean') { cap=e[2];m=e[1];e=e[0]; }
		
	if(!cap) { cap=false; }
	de='detachEvent'; // ie
	rel='removeEventListener'; // everything else
	if(typeof cn[rel] != 'undefined')
	{
		cn[rel](e,m,cap);
	} else if(typeof cn[de] != 'undefined')
	{
		cn[de]('on'+e,m);
	} else
	{
		cn["on"+e]=null;
	}
};
// parent getter
$pr.getparent=function()
{
	var cn=this.context.parentNode;
	
	while(cn.nodeType == 3 && cn.parentNode !== null)
	{
		cn=cn.parentNode;
	}
	
	return com.saltcollective.Phocus.DOM.getNode(cn);
};
$pr.setparent=function() { };
// position getter
$pr.getposition=function()
{
	var cn=this.context;
	
	var rtn=new phocus.Point(0,0);
	while(cn!==null)
	{
		var add=new phocus.Point(cn.offsetLeft,cn.offsetTop);
		rtn.add(add);
		cn=cn.offsetParent;
	}
	
	return rtn;
};
$pr.setposition=function(obj)
{
	this.set('position','absolute');
	this.set('x',obj.x);
	this.set('y',obj.y);
};
// position getter
$pr.getscroll=function()
{
	var cn=this.context;
	
	var rtn=new phocus.Point(0,0);
	if(typeof cn.scrollTop != 'undefined')
	{
		rtn.x=cn.scrollLeft;
		rtn.y=cn.scrollTop;
	}
	
	return rtn;
};
$pr.setscroll=function(obj)
{
	this.set('position','absolute');
	this.set('x',obj.x);
	this.set('y',obj.y);
};
// show / hide
$pr.hide=function()
{
	this.set('display','none');
};
$pr.show=function()
{
	this.set('display','');
};
// blur / focus
$pr.blur=function()
{
	this.context.blur();
};
$pr.focus=function()
{
	this.context.focus();
};
// dimensions getter
$pr.getdims=function()
{
	var cn=this.context;
	
	var rtn=new phocus.Point(cn.offsetWidth,cn.offsetHeight);
	
	return rtn;
};
$pr.setdims=function(obj)
{
	this.set('w',obj.x);
	this.set('h',obj.y);
};
// innerHTML setter/getter
$pr.setinnerHTML=function(val)
{
//	this.clear();
	var a=this.getnodes('*');
	for(var i=0;i<a.length;i++)
	{
		a.node(i).set('id','');
	}
	
	this.context.innerHTML=val;
};
$pr.getinnerHTML=function()
{
	return this.context.innerHTML;
};
// opacity setter
$pr.setalpha=function(a)
{
	if(phocus.Util.isIE())
	{
		if(typeof this.context.filters!='object' || typeof this.context.filters.alpha!='object' )
		{
			this.style.filter = 'alpha(opacity='+Math.round(a)+')';
		} else
		{
			this.context.filters.alpha.opacity=Math.round(a);
		}
	} else
	{
		this.style.opacity = Math.round(a*100)/10000;
	}
};
$pr.getalpha=function()
{
	var a=100;
	if(phocus.Util.isIE() && typeof this.context.filters=='object')
	{
		a=this.context.filters.alpha.opacity;
	} else
	{
		a=this.style.opacity*100;
	}
	return a;
};
// coloe setter
$pr.setcolour=function(c)
{
	this.style.color=this.colourParcel(c).toString();
};
$pr.setbgColour=function(c)
{
	this.style.backgroundColor=this.colourParcel(c).toString();
};
$pr.getcolour=function()
{
	return this.colourParcel(this.style.color);
};
$pr.getbgColour=function()
{
	return this.colourParcel(this.style.backgroundColor);
};
$pr.colourParcel=function(c)
{
	var colour=new phocus.Colour();
	if(typeof c == 'string')
	{
		var regexp=/(rgb)\(([0-9]+)[^0-9]*([0-9]+)[^0-9]*([0-9]+)\)|[a-fA-F0-9]{6}|[a-fA-F0-9]{3}|[a-fA-F0-9]{2}/; 
//		var regexp=/[a-fA-F0-9]{6}|[a-fA-F0-9]{3}|[a-fA-F0-9]{2}/;
		var col=c.match(regexp);
		// if we didn't match anything
		if(col === null) { col=['000000']; }
		// if we matched an RGB value
		else if(col[1] == 'rgb')
		{
			colour.setRGB(col[2],col[3],col[4]);
			return colour;
		}
		colour.setHEX(col[0]);
	} else if(!isNaN(c))
	{
		colour.setDEC(c);
	} else
	{
		colour.setDEC(0);
	}
	return colour;
};
// clear
$pr.clear=function()
{
	var n=this.context;
	if(n.hasChildNodes)
	{
		for(var j in n.childNodes)
		{
			if(n.childNodes.hasOwnProperty(j))
			{
				n.removeChild(n.childNodes[j]);
			}
		}
	}
};
com.saltcollective.Phocus.register(com.saltcollective.Phocus.DOM_node,'DOM_node');



com.saltcollective.Phocus.DOM_nodeset=function()
{
	this.nodeset=[];
	this.length=0;
};
$pr=com.saltcollective.Phocus.DOM_nodeset.prototype;
$pr.name='DOM_nodeset';
// to String
$pr.toString=function()
{
	var rtn='[';
	for(var i=0;i<this.nodeset.length;i++)
	{
		rtn+='['+i+']'+this.nodeset[i].toString()+(i<this.nodeset.length-1 ? ', ' : '');
	}
	return rtn+']';
};
// parse an array of nodes into the nodeset
// *** NOTE: Should addd shecking for nodes and node type in here
$pr.parsearray=function(nodeset /* :Array */)
{
	for(var i=0;i<nodeset.length;i++)
	{
		this.addelement(nodeset[i]);
	}
};
// join
// joins 2 DOM_nodesets together
// should add some type checking here
$pr.join=function(joiningnodeset)
{
	this.parsearray(joiningnodeset.nodeset);
	joiningnodeset.empty();
};
// empty
// deletes all node references contained in the nodeset
$pr.empty=function()
{
	this.nodeset.length=0;
};
// addelement
// adds a node to the DOM_nodeset object
$pr.addelement=function(node)
{
	// if we're a type 1 node then we need to make a new DOM_node Object
	// we should also add a check here for a DOM_node objct
	// if neither, return null
	if(typeof node != 'undefined' && node !==null && node.nodeType == 1)
	{
		node=com.saltcollective.Phocus.DOM.getNode(node);
	}
	this.nodeset.push(node);
	
//	this[this.length]=node;
	this.length=this.nodeset.length;
	this.firstnode=this.nodeset[0];
	this.lastnode=node;
};
// convenient nodeset wrapper
$pr.node=function(i)
{
	return this.nodeset[i];
};
/* lock and unlock */
$pr.lock=function()
{
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		this.nodeset[i].lock();
	}
};
$pr.unlock=function()
{
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		this.nodeset[i].unlock();
	}
};
// add / remove class
$pr.addclass=function(cn)
{
	if(typeof cn != 'string') { return; }
	
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		this.nodeset[i].addclass(cn);
	}
};
$pr.delclass=function(cn)
{
	if(typeof cn != 'string') { return; }
	
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		this.nodeset[i].delclass(cn);
	}
	
};
// implementing parent setters
$pr.set=function(prop,value,override)
{
	// a property is a template if it's an array and it has the same number of children as the nodeset
	var template=typeof value == 'object' && value.length == this.nodeset.length;
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		this.nodeset[i].set(prop,template ? value[i] : value,override);
	}
};
// implementing get
$pr.get=function(prop)
{
	var rtn=[];
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		rtn.push(this.nodeset[i].get(prop));
	}
	return rtn;
};
// implementing getElementById
$pr.getElementById=function(id)
{
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		this.nodeset[i].set(prop,value);
	}
};
// implementing add node. Multi purpose node addition.
// e:string[, m:string[, a:array[, t:text[, c:node[, n:number]]]]]
// e - the element to add
// m - mode. This determines where the node[s] are attached. legal values: BEFORE, AFTER, REPLACE, REPLACECHILDREN, BEGINNING, END (default: END)
// a - attributes : array of objects - [{p:property;v:variable},{p:property;v:variable}]
// t - text
// c - nodal context. will default to document if undefined. Allows you to add to, for example, all nodes under a specific node
// n - number. Will add the node 'n' number of times
$pr.addnode=function(e,m,a,t,c,n)
{
	var rtn=new com.saltcollective.Phocus.DOM_nodeset();
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		var rt=this.nodeset[i].addnode(e,m,a,t,c,n);
		rtn.join(rt);
	}
	return rtn;
};
// implementing add event
// e:string, m:method[, cap:node=false]
// e    - the event to add
// m    - The method to add
// cap  - Whether the event is applied during capture or bubble
$pr.setevent=function(e,m,cap)
{
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		this.nodeset[i].setevent(e,m,cap);
	}
};
$pr.unsetevent=function(e,m,cap)
{
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		this.nodeset[i].unsetevent(e,m,cap);
	}
};
// show / hide
$pr.deletenode=function()
{
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		this.nodeset[i].deletenode();
	}
};
// clone
$pr.getcopy=function()
{
	var rtn=new phocus.DOM_nodeset();
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		var copy=this.nodeset[i].getcopy();
		rtn.addelement(copy);
	}
	return rtn;
};
// show / hide
$pr.hide=function()
{
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		this.nodeset[i].hide();
	}
};
$pr.show=function()
{
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		this.nodeset[i].show();
	}
};
// blur / focus
$pr.blur=function()
{
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		this.nodeset[i].blur();
	}
};
$pr.focus=function()
{
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		this.nodeset[i].focus();
	}
};
// implementing getnodes
$pr.getnodes=function(query)
{
	var rtn=new com.saltcollective.Phocus.DOM_nodeset();
	for(var i=this.nodeset.length-1;i>=0;i--)
	{
		rtn.join(this.nodeset[i].getnodes(query));
	}
	return rtn;
};

com.saltcollective.Phocus.register(com.saltcollective.Phocus.DOM_nodeset,'DOM_nodeset');


// cleanup
$pr=null;