IZ = {};

dom = {
	//the basis of prototypal inheritance
    clone : function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    },

	//the result of the last query
	origin : new Array(),

	//the result of any new query
	result : null,

	//the css selector being evaluated
	css : null,

	//for the ready method
	loaded : null,

	// Current frame
	frame : window,

	// Current dom doc
	doc : document,

	//better than window.onload
	ready : function(f) {
		//is there a body element yet?
		if(!document.body) {
			//wait a few milliseconds, check again
			setTimeout('dom.ready(' + f + ')', 50);

			//stop here
			return false;
		}

		//alias
		var length = document.body.innerHTML.length;

		/**
		 * if our loaded variable is the same length
		 * as the innerHTML twice in a row, the body
		 * is fully loaded
		 */
		if(dom.loaded == length) {
			//and we can execute the function
			f();

			//dunno if this is necessary
			return true;
		}

		//otherwise we need 
		else {
			//otherwise we get the length
			dom.loaded = length;

			//and run the check again
			setTimeout('dom.ready(' + f + ')', 50);
		}
	},

	get : function(css) {
		//reset any result we might have
		this.result = new Array();

		//if they've passed a css selector...
		if(css.substr) {
			//start from here
			this.result = this.origin;

			//seperate the css selector by spaces...
			var css = css.split(' ');

			//and loop through each piece
			for(var i=0; i<css.length; i++) {
				//our other methods need access
				this.css = css[i];

				//if the selector contains a hash...
				if(this.css.match(/(\#)/)) {
					//we're looking for an element by its id
					this.get_by_id();
				}

				//if the selector has a period in it...
				else if(this.css.match(/(\.)/)) {
					//we're looking for elements of a certain class
					this.get_by_class();
				}

				//otherwise...
				else {
					//we want a certain set of elements
					this.get_by_tag();	
				}
			}
		}

		//is it an array?
		else if(css.join){
			this.result = css;
		}

		//or a single node?
		else {
			this.result.push(css);
		}

		//create a new dom object
		var dom_obj = this.clone(dom);

		//add the results
		dom_obj.origin = this.result;

		//clear the origin of the master object
		this.origin = new Array();

		//all done! ship it off
		return dom_obj;
	},

	// Allows queries to be run on a different frame
	frame: function(frame){		
		// Create a new dom object
		var domObj = this.clone(dom);
		
		// Change frames
		domObj.frame = frame;

		// Did they pass a string?
		(frame.substr) ?
			// Find and return the frame document from window.frames
			domObj.doc = this.getFrameDoc(window.frames[frame]):
			// Otherwise return the frame document directly
			domObj.doc = this.getFrameDoc(frame);
		
		// Make sure the object is fresh
		domObj.origin = new Array();

		// Give back the dom obj for chaining
		return domObj;
	},

	// Extract a frame's document object for use
	getFrameDoc: function(frame) {
		// Some corss browser joy here
		var doc = (frame.document) ? 
			// Most browsers use
			frame.document: 
			// But a few need
			frame.contentWindow || frame.contentDocument;

		// Return extracted doc
	    return doc;
	},

	/**
	 * Our $ function returns the actual element, rather
	 * than a cloned dom object. Can also be used to
	 * extract results from a dom object.
	 */
	$ : function(css){
		// Css selector or dom object?
		(css.substr) ?
			// Find the element
			this.get(css):
			// Or extract the result
			this.result = css.result;
		
		// More than one item in the result set?
		if(this.result.length > 1){
			// Return the set
			return this.result;
		// Otherwise...
		} else {
			// Return the one item
			return this.result[0];
		}
	},

	get_by_id : function() {		
		// We find a specific element
		var found = this.doc.getElementById(this.css.substr(1));

		// Add it to the results
		this.result.push(found);
	},

	get_by_tag : function() {		
		//if no starting point has been supplied...
		if(!this.result.length) {
			//begin with the body element
			this.result.push(this.doc.body);
		}

		//array to hold all elements found
		var matches = new Array();
	
		//for each element in our current results...
		for(var i=0; i<this.result.length; i++) {
			//find elements inside of the specified type...
			var found = this.result[i].getElementsByTagName(this.css);

			//and add each one...
			for(var j=0; j<found.length; j++) {
				//to the new result set
				matches.push(found[j]);
			}
		}

		//apply results
		this.result = matches;
	},

	get_by_class : function() {
		var css = this.css.split(".");

		/**
		 * if the user specified a set of tags to 
		 * look through, we get those first
		 */
		if(css[0]) {
			this.css = css[0];
			this.get_by_tag();
		}

		//array to hold all elements found
		var matches = new Array();

		//for each element in our current result set...
		for(var i=0; i<this.result.length; i++) {
			//convenience...
			var css_class = this.result[i].className;

			//if the classes match...
			if(css_class.match(css[1])) {
				//add element to the result set
				matches.push(this.result[i]);
			}
		}

		//apply results
		this.result = matches;
	},

	/**
	 * apply a function to each element in the 
	 * current result set
	 */
	each : function(f) {
		//for each element in the result set...
		for(var i=0; i<this.origin.length; i++) {
			//assign the function...
			this.origin[i].temp = f;
			
			//execute...
			this.origin[i].temp();
			
			//and remove
			this.origin[i].temp = null;
		}
	},

	// Wrapper for the each method
	on : function(e,f){
		// That attaches an event
		this.each(function(){
			// To each item in the result set
			eval("this.on" + e + "=" + f);
		});
	},

	// Removes node(s) from the dom
	nix : function(nodes){
		// Passed an array of nodes?
		var kill = (nodes.join) ?
			// Use their array
			kill = nodes:
			// Or add the single node
			kill = new Array(nodes);

		// Loop through the nodes
		for(i=0; i<kill.length; i++){
			// Alias
			var node = kill[i];

			// Find the node's parent and remove
			node.parentNode.removeChild(node);
		}
	},

	// Easy way to create elements
	create : function(node, attributes) {
		// Create the specified element
		var node = this.doc.createElement(node);
		
		// Was an attribute collection passed?
		if(attributes) {
			// Loop through each item
			for(x in attributes) {
				// And attach them to the newly created node
				eval("node." + x + "='" + attributes[x] + "'");
			}
		}

		/**
		 * Return a dom instantiation with this node
		 * in the result set, and the correct frame
		 */
		return dom.get(node);
	},

	// Wrapper for each that
	before : function(node) {
		// Loops through the result set...
		this.each(function(){
			// And appends each item before the node
			node.parentNode.insertBefore(this, node);
		});

		// Return this instantiation
		return this;
	},

	inside : function(node) {
		//loop through nodes and...
		this.each(function(){
			//append them before the specified element
			node.appendChild(this);
		});

		// Return this instantiation
		return this;
	},

	// Replaces a node with the current result set
	replace : function(node) {
		// Loop through the result set
		this.each(function(){
			// Add item before the specified node
			node.parentNode.insertBefore(this, node);
		});

		// Delete the node
		this.nix(node);
		
		// Return this instantiation
		return this;
	},

	append : function(node) {
		//loop through nodes and...
		this.each(function(){
			//append them before the specified element
			this.appendChild(node);
		});

		// Return this instantiation
		return this;
	},

	/**
	 * find an element's position on the page.
	 * thank you ppk and coda
	 */
	xy : function(obj) {
		//create some empty vars
		var curleft = curtop = 0;

		//add the offset values
		do {
			curleft += obj.offsetLeft
			curtop += obj.offsetTop
		}

		//while there is an offset parent
		while(obj = obj.offsetParent)

		//return the result
		return [curleft,curtop];
	},

	/**
	 * Returns a computed css value for a specific 
	 * element. Supposedly somewhat unreliable. 
	 * Seems to work fine for me.
	 */
	get_style : function(element,prop) {
		// For internet explorer...
		if(element.currentStyle) {
			// We have something special
			return element.currentStyle[prop];
		}

		// Everyone else...
		else {
			// Uses another method
			return document.defaultView.getComputedStyle(element,null).getPropertyValue(prop);
		}
	},

	//yay ajax!
	ajax : function(path, callback){
		//browser juggle
		request = (window.XMLHttpRequest) ?
			//standards compliant
			new XMLHttpRequest():
			//ie6 flavor
			new ActiveXObject("Microsoft.XMLHTTP");

		request.onreadystatechange = function() {
			//request is all good
			if (request.readyState == 4 && request.status == 200) {
				//get response type
				var ctype = request.getResponseHeader("Content-Type");

				//did we get an xml response?
				response = (ctype.match(/xml/)) ? 
					//send back xml
					request.responseXML: 
					//send back text
					request.responseText;

				//set the response text
				if(callback) callback(response);
			}
		}
		
		// Empty variable string
		var vars = "";
		
		// Path was a string
		if(path.substr){		
			// Prime a GET request
			request.open('GET', path, true);
			
			// Send the request
			request.send(null);
		}

		// Path was an object
		else {
			// Now check and see if vars is a string
			if(path.vars.substr){
				// Yup, use it as is
				vars = path.vars;
			}

			// Vars is an object so...
			else {
				// Construct a string
				for(x in path.vars) {
					// Out of the members
					vars += "&" + x + "=" + path.vars[x];
				}

				// Remove the first ampersand
				vars = vars.substr(1);
			}

			// Prime a POST request
			request.open('POST', path.url, true);

			// Necessary POST headers
			request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

			// Send the request
			request.send(vars);
		}
	},

	/**
	 * Ajax wrapper that loads responseText into 
	 * the current result set's innerHTML
	 */
	load : function(path){
		// Closure variable
		var dom = this;

		// Ajax in the requested path
		dom.ajax(path, function(response){
			// And for each item in the dom object
			dom.each(function(){
				// Inject the response
				this.innerHTML = response;
			});
		});
	},
	
	// Stop event bubbling, credit goes to PPK
	nobubble: function(e) {		
		// IE
		if (!e) var e = window.event;
		
		// Also IE
		e.cancelBubble = true;
		
		// Everybody else
		if (e.stopPropagation) e.stopPropagation();
	}
}