/* Need to do something about the processInstructions and comments */

System.Xml = new Object()
System.Xml.Version = ".1"

System.Xml.Node = __System_Xml_Node
System.Xml.Document = __System_Xml_Document
System.Xml.Element = __System_Xml_Element
System.Xml.Attribute = __System_Xml_Attribute
System.Xml.Declaration = __System_Xml_Declaration
System.Xml.Comment = __System_Xml_Comment
System.Xml.DocumentFragment = __System_Xml_DocumentFragment
System.Xml.CDATASection = __System_Xml_CDATASection
System.Xml.Text = __System_XmlText // INCOMPLETE
System.Xml.ProcessingInstruction = __System_Xml_ProcessingInstruction // Not done
System.Xml.NodeList = Array
//System.Xml.NodeList.item = XMLNodeList_Item
System.Xml.NamedNodeMap = System.Array//Array
/*System.Xml.NamedNodeMap.getNamedItem = XMLNamedNodeMap_GetNamedItem
System.Xml.NamedNodeMap.getNamedItemNS = XMLNamedNodeMap_GetNamedItemNS
System.Xml.NamedNodeMap.item = XMLNamedNodeMap_Item
System.Xml.NamedNodeMap.removeNamedItem = XMLNamedNodeMap_RemoveNamedItem
System.Xml.NamedNodeMap.removeNamedItemNS = XMLNamedNodeMap_RemoveNamedItemNS
System.Xml.NamedNodeMap.setNamedItem = XMLNamedNodeMap_SetNamedItem
System.Xml.NamedNodeMap.setNamedItemNS = XMLNamedNodeMap_SetNamedItemNS*/

System.Xml.GetTags = __System_Xml_GetTags
System.Xml.GetTagName = __System_Xml_GetTagName
System.Xml.NODE_ELEMENT = 1
System.Xml.NODE_Attribute = 2
System.Xml.NODE_TEXT = 3
System.Xml.NODE_CDATA_SECTION = 4
System.Xml.NODE_NODE_ENTITY_REFERNCE = 5
System.Xml.NODE_ENTITY = 6
System.Xml.NODE_PROCESSING_INSTRUCTIONS = 7
System.Xml.NODE_COMMENT = 8
System.Xml.NODE_DOCUMENT = 9
System.Xml.NODE_DOCUMENT_TYPE = 10
System.Xml.NODE_DOCUMENT_FRAGMENT = 11
System.Xml.NODE_NOTATION = 12
System.Xml.LOADING = 1
System.Xml.LOADED = 2
System.Xml.INTERACTIVE = 3
System.Xml.COMPLETED = 4

function __System_Xml_Node() {
	this.attributes = new System.Xml.NamedNodeMap()
	this.childNodes = new System.Xml.NodeList()
	this.firstChild = null
	this.lastChild = null
	this.localName = new String() //Not done
	this.namespaceURI = new String() //Not done
	this.nextSibling = null //Not done
	this.nodeName = new String()
	this.nodeType = new String() //Not done
	this.nodeValue = new String()
	this.ownerDocument = null //Not done
	this.parentNode = null
	this.prefix = null //Not done
	this.previousSibling = null //Not done
	this.textContent = null //Not done
	this.New = __System_Xml_Node_New
	this.ToElement = System.Xml.Element
	this.ToDocument = System.Xml.Document
	this.ToAttribute = System.Xml.Attribute
	this.ToDeclartion = System.Xml.Declaration
	this.ToComment = System.Xml.Comment
	this.ToDocumentFragment = System.Xml.DocumentFragment
	
	this.appendChild = __System_Xml_Node_AppendChild
	this.cloneNode = __System_Xml_Node_CloneNode
	this.hasAttributes = __System_Xml_Node_HasAttributes
	this.hasChildNodes = __System_Xml_Node_HasChildNodes
	this.insertBefore = __System_Xml_Node_InsertBefore
	this.isSupported = __System_Xml_Node_IsSupported
	this.normalize = __System_Xml_Node_Normalize
	this.removeChild = __System_Xml_Node_RemoveChild
	this.replaceChild = __System_Xml_Node_ReplaceChild
	
	
}

function __System_Xml_Document(sXML) {
	this.Inherit = __System_Xml_Node
	this.loadXML = __System_Xml_Document_LoadXML
	this.documentElement = new System.Xml.Element()
	this.getElementById = __System_Xml_Document_GetElementById
	this.getElementsByTagName = __System_Xml_Document_GetElementsByTagName

	//this.getElementsByTagNameNS = __System_Xml_Document_GetElementsByTagNameNS // NOT IMPLEMENTED
	//this.importNode = __System_Xml_Document_ImportNode // NOT IMPLEMENTED
	
	//this.declaration = new System.Xml.Declaration() // Not standard
	
	this.createAttribute = __System_Xml_Document_CreateAttribute
	this.createAttributeNS = __System_Xml_Document_CreateAttributeNS
	this.createCDATASection = __System_Xml_Document_CreateCDATASection
	this.createComment = __System_Xml_Document_CreateComment
	this.createDocumentFragment = __System_Xml_Document_CreateDocumentFragment
	this.createElement = __System_Xml_Document_CreateElement
	this.createElementNS = __System_Xml_Document_CreateElementNS
	this.createEntityReference = __System_Xml_Document_CreateEntityReference
	this.createProcessingInstruction = __System_Xml_Document_CreateProcessingInstruction
	this.createTextNode = __System_Xml_Document_CreateTextNode
	
	
	this.createNode = __System_Xml_Document_CreateNode // Private non-standard
	this.nodeType = System.Xml.NODE_DOCUMENT
	//alert(sXML != null)
	this.Inherit()
	if (sXML != null) {
		this.loadXML(sXML)
	}
}

function __System_Xml_Comment() {
	this.nodeType = System.Xml.NODE_COMMENT
	this.data = new String()
	/*this.appendData = __System_Xml_Comment_AppendData
	this.deleteData = __System_Xml_Comment_DeleteData
	this.insertData = __System_Xml_Comment_InsertData
	this.replaceData = __System_Xml_Comment_ReplaceData*/
	
}

function __System_Xml_Text() {
}

function __System_Xml_ProcessingInstruction() {

}

function __System_Xml_Declaration() {
	this.attributes = new Array()
	this.baseURI = ""
	this.encoding = "utf-16"
	this.innerText = ""
	this.localName = ""
	this.name = ""
	this.nodeType = System.Xml.NODE_PROCESSING_INSTRUCTIONS
	this.ownerDocument = this.ParentNode
	this.prefix = "?xml"
	this.standalone = true
	this.version = "1.0"
}

function __System_Xml_DocumentFragment() {
	this.nodeType = System.Xml.XMLDocumentFragment

}

function __System_Xml_CDATASection() {
	this.nodeType = System.Xml.XMLCDATASection
}

function __System_Xml_NodeList_Item(Index) {
	return(this[Index])
}


function __System_Xml_Element(sXML, Parent) {
	this.Inherit = __System_Xml_Node
	this.Inherit()

	//this.attributes = new Array()
	this.getElementById = __System_Xml_Document_GetElementById
	this.getElementsByTagName = __System_Xml_Document_GetElementsByTagName
	//this.parentNode = null
	this.siblings = null // Not standard
	//this.firstChild = null
	//this.lastChild = null
	this.createNode = __System_Xml_Document_CreateNode // Not standard
	this.nodeType = System.Xml.NODE_ELEMENT
	this.id = new String() // Not standard
	
	if (typeof(Parent) == "object") {
		this.parentNode = Parent
		if (typeof(Parent.firstChild) != "object") {
			Parent.firstChild = this
		}
		
		Parent.lastChild = this
	}
	
	this.nodeValue = ""
	this.innerXML = new String() // Not standard
	this.childNodes = new System.Xml.NodeList()
	this.nodeName = new String()
	this.name = new String()
	this.prefix = new String()
	this.New = __System_Xml_Element_New
	
	if (sXML != null) {
		this.New(sXML)
	}
}

function __System_Xml_Node_New() {
	switch (this.nodeType) {
		case System.Xml.NODE_ELEMENT:
			this.ToElement()
			break
		case System.Xml.NODE_DOCUMENT:
			this.ToDocument()
			break
		case System.Xml.NODE_ATTRIBUTE:
			this.ToAttribute()
			break
		case System.Xml.NODE_DECLARATION:
			this.ToDeclaration()
			break
		case System.Xml.NODE_COMMENT:
			this.ToComment()
			break
		case System.Xml.NODE_DOCUMENT_FRAGMENT:
			this.ToDocumentFragment()
			break
	}
}

function __System_Xml_Document_CreateAttribute(name) {
	var Node = new System.Xml.Attribute()
	Node.name = name
	return (Node)
}
function __System_Xml_Document_CreateAttributeNS(namespaceURI, qualifiedName) {
	var Node = new System.Xml.Attribute()
	Node.name = qualifiedName
	Node.nodeName = qualifiedName
	Node.namespaceURI = namespaceURI
	var Name = new Array(qualifiedName.split(":"))
	if (Name.length == 2) {
		Node.prefix = Name[0]
		Node.localName = Name[1]
	}
	return (Node)
}
function __System_Xml_Document_CreateCDATASection(data) { // <----- NOT IMPLEMENTED FULLY
	return (new System.Xml.CDATASection())
}
function __System_Xml_Document_CreateComment(data) {
	var Node = new System.Xml.Comment()
	Node.data = data
	return (Node)
}
function __System_Xml_Document_CreateDocumentFragment() {
	return (new System.Xml.DocumentFragment())
}

function __System_Xml_Document_CreateElement(tagName) {
	var Node = new System.Xml.Element()
	Node.tagName = tagName
	return (Node)
}

function __System_Xml_Document_CreateElementNS(namespaceURI, qualifiedName) {
	var Node = new System.Xml.Element()
	Node.nodeName = qualifiedName
	Node.namespaceURI = namespaceURI
	var Name = new Array(qualifiedName.split(":"))
	if (Name.length == 2) {
		Node.prefix = Name[0]
		Node.localName = Name[1]
	}
	Node.tagName = qualifiedName
	return (Node)
}

function __System_Xml_Document_CreateEntityReference(name) { // <----- NOT IMPLEMENTED FULLY

}

function __System_Xml_Document_CreateProcessingInstruction(target, data) {  // <----- NOT IMPLEMENTED FULLY
	return(new System.Xml.ProcessingInstruction())
}

function __System_Xml_Document_CreateTextNode(data) {
	// INCOMPLETE
	return(new System.Xml.TextNode)
}

function __System_Xml_Attribute(Name, Value) {
	this.Inherit = __System_Xml_Node
	this.Inherit()
	
	this.name = new String(Name)
	this.ownerElement = null //Not used
	this.specified = new Boolean(false) //Not used
	this.value = new String(Value)
}

function __System_Xml_Document_CreateNode(StringArray, Parent) {
	var Nodes = new Array()
	var StartNode = new String()
	var EndNode = new String()
	var StartIndex = new Number(-1)
	var EndIndex = new Number(-1)
	var NodeName = new String()
	var ReturnNodes = new Array()
	var InnerXML = new String()
	var OuterXML = new String()
	var sAttributes = new String()

	if (typeof(StringArray) == "string") {
		Nodes = System.Xml.GetTags(StringArray)
	} else {
		Nodes = StringArray
	}
	
	// Find the first XML element in the array
	// Due to whitespace it may not be the first element
	for (var I = 0; I < Nodes.length; I++) {
		if (StartNode == "") {
			if (Nodes[I].charAt(0) == "<") {
				StartNode = Nodes[I]
				StartIndex = new Number(I)
				// Get the node's name
				NodeName = StartNode.substr(1, StartNode.search(new RegExp(/[>\s*]/)) - 1)
				
				sAttributes = StartNode.substr(NodeName.length + 1, StartNode.length - 2 - NodeName.length)
				
				OuterXML = StartNode
				var TokenEnd = StartNode.charAt(StartNode.length - 2)
				if (TokenEnd == "?" || TokenEnd == "/" || TokenEnd == "-") {
					EndNode = Nodes[I]
					EndIndex = I
					if (TokenEnd == "?") {
						sAttributes = sAttributes.substr(0, sAttributes.lastIndexOf("?") - 1)
					} else if (TokenEnd == "/") {
						sAttributes = sAttributes.substr(0, sAttributes.lastIndexOf("/") - 1)
					}
				}
			}
		} else {
			if (Nodes[I] == "</" + NodeName + ">") {
				EndNode = Nodes[I]
				EndIndex = new Number(I)
				OuterXML += Nodes[I]
			} else {
				InnerXML += Nodes[I]
				OuterXML += Nodes[I]
			}
		}
		
		if (StartIndex >= 0 && EndIndex >= 0) {
			// Find the type of node
			var Node

			if (NodeName.charAt(0) == "?") {
				Node = new System.Xml.Declaration()
			} else if (NodeName.substr(0, 3) == "!--") {
				Node = new System.Xml.Comment()
			} else {
				Node = new System.Xml.Element()
			}
			
			//Node.name = NodeName // Took out because .name is not part of the standard
			Node.nodeName = NodeName
			var QualifiedName = new Array(NodeName.split(":"))
			
			if (Name.length == 2) {
				Node.prefix = QualifiedName[0]
				Node.localName = QualifiedName[1]
			}

			Node.tagName = NodeName
			
			Node.innerXML = InnerXML
			Node.outerXML = OuterXML
			Node.parentNode = Parent
			
			if (Parent.firstChild == null) {
				Parent.firstChild = Node
			}
			
			Parent.lastChild = Node

			// Manipulate the attributes of the tag
			if (Node.nodeType != System.Xml.NODE_COMMENT) {
				var Attributes = new Array()

				Attributes = sAttributes.split(new RegExp(/=\s*['"]|['"]\s*/))

				// Clean up the Attribute's name
				for (var J = 0; J < Attributes.length; J += 2) {
					Attributes[J] = Attributes[J].replace(new RegExp(/\s/g), "")
				}
				
				if (Attributes.length > 1) {
					for (var J = 0; J < Attributes.length; J++) {			
						Node.attributes.Add(new System.Xml.Attribute(Attributes[J].replace("=", ""), Attributes[J + 1]))
						if (Node.nodeType == System.Xml.NODE_PROCESSING_INSTRUCTIONS) {
							switch (Attributes[J].toUpperCase()) {
								case "VERSION":
									Node.version = Attributes[J + 1]
									break
								case "ENCODING":
									Node.encoding = Attributes[J + 1]
									break
								case "STANDALONE":
									Node.standalone = Attributes[J + 1]
									break
							}
						} else if (Node.nodeType == System.Xml.NODE_ELEMENT) {
							if (Attributes[J].toUpperCase() == "ID") {
								Node.id = Attributes[J + 1]
							} else if (Attributes[J].toUpperCase() == "VALUE") {
								Node.value = Attributes[J + 1]
								Node.nodeValue = Node.value
							} else if (Attribute[J].toUpperCase() == "XMLNS") {
								Node.namespaceURI = Attributes[J + 1]
							}
						} else if ((Node.nodeType == System.Xml.NODE_ATTRIBUTE) {

						} else if (Node.nodeType == System.Xml.NODE_COMMENT) {
							alert(Node.outerXML)
						}
						
						J++
					}
				}
			} else if (Node.nodeType == System.Xml.NODE_COMMENT) {
				sAttributes = sAttributes.slice(0, sAttributes.length - 2)
				
				var IsDone = new Boolean(false)
				while(IsDone == false) {
					if (sAttributes.charAt(0) == " ") {
						sAttributes = sAttributes.slice(1, sAttributes.length - 1)
						IsDone = false
					} else {
						IsDone = true
					}
					
					if (sAttributes.charAt(sAttributes.length - 1) == " ") {
						sAttributes = sAttributes.slice(0, sAttributes.length - 1)
						IsDone = false
					} else {
						IsDone = true
					}
				}
				
				Node.data = sAttributes
			}
			
			// Check to see if the node has children
			if (InnerXML.indexOf("<") >= 0) {
				// The node has children
				
				var Children = this.createNode(Nodes.slice(StartIndex + 1, EndIndex), Node)
				if (Children != null && Children.length > 1) {
					Node.childNodes = Node.childNodes.concat(Children)
				} else {
					Node.childNodes[Node.childNodes.length] = Children
				}
			} else if (EndIndex - 2 == StartIndex && StartIndex != EndIndex) {
				Node.value = Nodes[StartIndex + 1]
				Node.nodeValue = Node.value
			}
			
			if (Node.nodeType != System.Xml.NODE_CDATA_SECTION && Node.nodeType != System.Xml.NODE_COMMENT ) {
				ReturnNodes[ReturnNodes.length] = Node
			}
			
			StartNode = new String()
			EndNode = new String()
			StartIndex = new Number(-1)
			EndIndex = new Number(-1)
			NodeName = new String()
			InnerXML = new String()
			OuterXML = new String()
		}
	}
	
	if (ReturnNodes.length > 1) {
		return(ReturnNodes)
	} else {
		return(ReturnNodes[0])
	}
}

function __System_Xml_Document_LoadXML(sXML) {
	// Clean XML to get rid of the instructions
	// Take the root node and create an element. Children should be made automatically

	var Elements = System.Xml.GetTags(sXML)
	
	var Node = this.createNode(Elements, this)
	
	if (Node == null) {
		return
	}
	
	for (var I = 0; I < Node.length; I++) {
		if (Node[I].nodeType == System.Xml.NODE_PROCESSING_INSTRUCTIONS) {
			this.declaration = Node[I]
		} else if (Node[I].nodeType == System.Xml.NODE_ELEMENT) {
			this.documentElement = Node[I]
			this.childNodes.add(Node[I])
		}
	}
	
	return(true)		
}


function __System_Xml_GetTags(sXML) {
	var arrTemp = new Array()
	var arrTokens = new Array()
	
	//iterate through the characters
	for (var I = 0; I < sXML.length; I++) {
		var C = sXML.charAt(I)
		
		//push this character into the temporary array
		if (C != "<") {
			arrTemp.push(C)
		}

		//check the value
		switch (C) {
			case '<':
				if (arrTemp.length > 0) {
					arrTokens.push(arrTemp.join(""))
					delete arrTemp
					arrTemp = new Array()
				}
				arrTemp.push("<")
				break
		 	case '>':
				arrTokens.push(arrTemp.join(""))
				delete arrTemp
				arrTemp = new Array()
		}
	
	}

	return(arrTokens)
}

function __System_Xml_Element_New(Node) {
	/*for (var I = 0; I < Node.length; I++) {
		if (Node[I][0] == "<") {
			
		}
	}*/
	
	
	//this.LoadXML(Node)
}

function __System_Xml_GetTagName(sXML) {
	var Elements = sXML.XML.split(" ")
	return(Elements[0].substr(1, Elements[0].length - 1))
}

function __System_Xml_Document_GetElementById(elementID) {
	var Nodes = this.childNodes
	
	for (var I = 0; I < Nodes.length; I++) {
		var Element = Nodes[I]

		if (typeof(Element.attributes.Item(elementID, "Value")) == "object") {
			if (Element.attributes.Item(elementID, "Value").value == elementID && (Element.attributes.item(elementID, "Value").name == "ID" || "id")) {
				return(Element)
			}
		}
	}
	
	// Search through all the children's children
	for (var I = 0; I < Nodes.length; I++) {
		var Element = Nodes[I].getElementById(elementID)
		
		if (typeof(Element) == "object") {
			if (Element.attributes.item(elementID, "Value").Value == elementID && (Element.attributes.item(elementID, "Value").Name == "ID" || "id")) {
				return(Element)
			}
		}
	}
}

function __System_Xml_Document_GetElementsByTagName(tagName) {
	var Elements = new Array()
	var Nodes = this.childNodes
	
	for (var I = 0; I < Nodes.length; I++) {
		var Element = Nodes[I]
		if (Element.name == tagName) {
			Elements[Elements.length] = Element
		}
	}
	
	// Search through all the children's children
	for (var I = 0; I < Nodes.length; I++) {	
		var Element = Nodes[I]
		
		if (Element.getElementsByTagName.length > 0) {
			Elements = Elements.concat(Element.getElementsByTagName(tagName))
		}
	}

	return(Elements)
}

function __System_Xml_Document_ToString() {
	
}

function __System_Xml_Node_AppendChild(newChild) {
	newChild.parentNode = this
	this.childNodes[this.childNodes.length] = newChild
	return(newChild)
}

function __System_Xml_Node_CloneNode(deep) {
	if (typeof(deep) != "boolean") {
		deep = new Boolean(false)
	}

	var Node = this.Copy()

	if (deep == false) {
		Node.childNodes = new System.Xml.NodeList()
	}
	
	Node.parentNode = null
	return(Node)
}

function __System_Xml_Node_HasAttributes() {
	if (this.nodeType == System.Xml.NODE_ATTRIBUTE) {
		if (this.attributes.length > 0) {
			return(true)
		}
	}
	return(false)		
}

function __System_Xml_Node_HasChildNodes() {
	if (this.nodeType == System.Xml.NODE_ATTRIBUTE) {
		if (this.childNodes.length > 0) {
			return(true)
		}
	}
	return(false)
}

function __System_Xml_Node_InsertBefore(newChild, refChild) {
	newChild.parentNode = this
	// update the InnerXML, OuterXML to reflect the changes of the added Node
	
	for (var I = 0; I < this.childElements.length; I++) {
		if (this.childElements[I] == refChild) {
			if (I == 0) {
				var Ar = new Array(newChild)
				Ar = Ar.concat(this.childElements)
				this.childElements = Ar
			} else {
				var StartElements = new Array(this.childElement.slice(0, I - 1))
				var EndElements = new Array(this.childElements.slice(I))
				StartElements = StartElements.concat(new Array(newChild), EndArray)
				this.childElements = StartElements
			}
			break
		}
	}
	
	return(newChild)
}

function __System_Xml_Node_IsSupported(feature, version) { // Not truely supported
	return(true)
}

function __System_Xml_Node_Normalize() { // Not implemented
}

function __System_Xml_Node_RemoveChild(oldNode) {
	for (var I = 0; I < this.childNodes; I++) {
		if (this.childNodes[I] == oldNode) {
			return(this.childNodes.Remove(I))
		}
	}
}

function __System_Xml_Node_ReplaceChild(newChild, oldChild) {
	newNode.parentNode = this
	
	for (var I = 0; I < this.childNodes; I++) {
		if (this.childNodes[I] == oldNode) {
			this.childNodes[I] = newNode
			oldNode.parentNode = null
			return(oldNode)
		}
	}
}