var XmlData = Class.create({
	initialize: function(inNode) {
		this.node = inNode;
		if(!this.node) throw {message: '[XmlData] Invalid node'};
	},
	getXml: function() {
		return this.node;
	},
	// Get the content of an XML tag
	// e.g. getTagContent('p') on '<a><p>text1</p></a><p>text2</p>' returns 'text1'
	getTagContent: function(inTag) {
		var myElements = this.node.getElementsByTagName(inTag);
		
		if(0 == myElements.length || null == myElements[0].firstChild) return null;
		
		return myElements[0].firstChild.nodeValue;
	},
	getMultipleTagsContent: function(inTags) {
		var outTagsContent = {};
		var i;
		
		for(i=0; i<inTags.length; i++) {
			outTagsContent[inTags[i]] = this.getTagContent(inTags[i]);
		}
		
		return outTagsContent;
	},
	getAllTagsContent: function(inTag) {
		var i, j;
		var myNodes = this.findNodesByTag(inTag);
		var outElements = [];
		
		j = 0;
		for(i=0; i<myNodes.length; i++) {
			var myCurrentNode = myNodes[i];
			
			if(myCurrentNode.node
			   && myCurrentNode.node.firstChild
			   && myCurrentNode.node.firstChild.nodeValue
			) {
				outElements[j++] = myCurrentNode.node.firstChild.nodeValue;
			} else {
				outElements[j++] = null;
			}
		}
		
		return outElements;
	},
	// Get an XML tag's attributes
	// inAttributes: array of attributes
	getTagAttributes: function(inTag, inAttributes) {
		var myNode;
		var myProperty;
		var outProperties = {};
		var i = 0;
		
		// Check if the root node matches the creteria
		if(this.node.tagName == inTag) {
			myNode = this.node;
		} else {
			var myElements = this.node.getElementsByTagName(inTag);
			if(0 == myElements.length) return outProperties;
			myNode = myElements[0];
		}
		
		for(var i=0; i<inAttributes.length; i++) {
			outProperties[inAttributes[i]] = myNode.getAttribute(inAttributes[i]);
		}
		
		return outProperties;
	},
	// Get all the nodes for a given attributes set
	// inAttributes: object containing key/value attributes pairs to match
	findNodeByAttributes: function(inTag, inAttributes) {
		var myElements = this.node.getElementsByTagName(inTag);
		var myNode;
		var myAttribute;
		var myXmlAttribute;
		
		if(null == inAttributes && myElements.length>0) return myElements[0];
		
		for(myNode=0; myNode<myElements.length; myNode++) {
			for(myAttribute in inAttributes) {
				myXmlAttribute = myElements[myNode].getAttribute(myAttribute);
				if(myXmlAttribute && myXmlAttribute == inAttributes[myAttribute]) {
					return new XmlData(myElements[myNode]);
				}
			}
		}
		
		return null;
	},
	// Get all the nodes for a given tag name
	findNodesByTag: function(inTag) {
		var myElements = this.node.getElementsByTagName(inTag);
		var myNode;
		var outElements = [];
		
		for(myNode=0; myNode<myElements.length; myNode++) {
			outElements[myNode] = new XmlData(myElements[myNode]);
		}
		
		return outElements;
	},
	getAllTagsAttributes: function(inTag, inAttributes) {
		var i, j;
		var myNodes = this.findNodesByTag(inTag);
		var outElements = [];
		
		j = 0;
		for(i=0; i<myNodes.length; i++) {
			outElements[j++] = myNodes[i].getTagAttributes(inTag, inAttributes);
		}
		
		return outElements;
	},
	inspect: function() {
		var myString = '';
		
		try {
			var mySerializer = new XMLSerializer();
			myString = mySerializer.serializeToString(this.node);
		} catch (e) {
			myString = this.node.xml;
		}
		
		return myString.gsub('><', '>\n<');
	}
});

var XmlBuffer = Class.create(XmlData, {
	initialize: function($super, inNode, inDocRoot) {
		this.docroot = (inDocRoot) ?
			inDocRoot : this.createXmlDocument();
		
		if(inNode) $super(inNode);
		else $super(this.docroot);
	},
	//addStandardHeader: function() {
	//	if(this.findNodesByTag('xml').length) return;
	//	this.addTag('xml')
	//},
	getXml: function() {
		return this.docroot;
	},
	createXmlDocument: function() {
		var myXmlDocument = null;
		
		if (document.implementation
			&& document.implementation.createDocument) {
			myXmlDocument =
				document.implementation.createDocument("", "", null);
			myXmlDocument.async = false;
		}
		else if (window.ActiveXObject) {
			myXmlDocument = new ActiveXObject("Microsoft.XMLDOM");
			myXmlDocument.async = false;
	 	}
		
		return myXmlDocument;
	},
	// Add a named tag with a given attributes set
	// inAttributes: object containing key/value attributes pairs to set
	addTag: function(inName, inAttributes, inText) {
		var myNode = this.docroot.createElement(inName);
		
		if(inAttributes) {
			for(myAttribute in inAttributes) {
				myNode.setAttribute(myAttribute, inAttributes[myAttribute]);
			}
		}
		
		if(inText) myNode.appendChild(this.docroot.createTextNode(inText));
		this.node.appendChild(myNode);
		
		return new XmlBuffer(myNode, this.docroot);
	}
});
