﻿//	**************************************************************************
//	Jena - Javascript Library (XML)
//
//	Written by Robert Swiston
//
//	Copyright 2010, RomiDesigns - All Rights Reserver
//
//	No part of this script may be reproducted or altered without the
//	expressed consent of RomiDesigns or its representative(s)
//	**************************************************************************

var jenaXmlNode = function(pNode)
{
	function GetNodeValue()
	{
		var RetValue = pNode.childNodes[0] != undefined ? pNode.childNodes[0].nodeValue : (pNode.nodeValue != undefined ? pNode.nodeValue : "" );;

		for (var iNode = 1; iNode < pNode.childNodes.length; iNode++)
		{ 
			if (pNode.childNodes[iNode].nodeName == "#text")
			{
				RetValue += (pNode.childNodes[iNode] != undefined ? pNode.childNodes[iNode].nodeValue : "" );
			}
		}
		
		return RetValue;
		
	};
	var ValueOfNode = GetNodeValue();
	
	this.Node = pNode;
	this.value = GetNodeValue();
	this.name = pNode.nodeName;
	this.length = pNode.childNodes.length;
	
	this.attribute = function(pName)
	{
		return pNode.attributes.getNamedItem(pName).value;
	};
	this.node = function(xPath)
	{
		return this.nodes(xPath)[0];
	};	
	this.nodes = function(xPath)
	{
		return jenaXmlParser(this.Node).parse(xPath);
	};	
	this.child = function(pInteger)
	{
		if (this.Node.childNodes.length > pInteger)
		{
			return new jenaXmlNode(this.Node.childNodes[pInteger]);
		}
		else
		{
			return null;
		}
	};
	this.childNodes = function()
	{
		var retNodes = [];
		for (var iChild = 0; iChild < this.Node.childNodes.length; iChild++)
		{
			retNodes.push(new jenaXmlNode(this.Node.childNodes[iChild]));
		}
		return retNodes;
	};
};

function jenaXmlParser(pRoot)
{
	var Nodes = [];
	var RetValue = this;
	
	this.testCriteria = function(pNode, iNode)
	{
		var XmlNode = new jenaXmlNode(pNode);
		
		if (1==1)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	this.getXPathCriteria = function(pPath)
	{
		var Criteria = null;		
		var Matches = new String(pPath.match(/\[[^\]]*\]/g));
		
		if (!Matches.isNullOrEmpty())
		{
			var Func = this.testCriteria.toString();
			
			Criteria = Matches.split("],[");
			for (var j = 0; j < Criteria.length; j++)
			{
				Criteria[j] = Criteria[j].replace("[", "").replace("]", "");
				
				pPath = pPath.replace("[" + Criteria[j] + "]", "");
				
				if (Criteria[j].indexOf("@") == 0)
				{
					Criteria[j] = Criteria[j].replace(/@([a-zA-Z0-9]*)(\s?[!<>=]?=\s?)[\x22\x27]?([a-zA-Z0-9\s]*)[\x22\x27]?/,"pNode.getAttribute(\"$1\") $2 \"$3\"");
				}
				else if (Criteria[j].indexOf(".") == 0)
				{
					Criteria[j] = Criteria[j].replace(/\.((indexOf|substring)\(([\x22\x27][^\x22\x27]*[\x22\x27]|\d*(,\s?\d)?)\))?(\s?[!<>]?=?\s?)(\d|[\x22\x27][^\x22\x27]*[\x22\x27])/, "XmlNode.value$1 $5 $6");
				}
				else
				{
					Criteria[j] = Criteria[j].replace(/(\d{1,3})/, "iNode == $1");
				}
				
				Func = Func.replace(/1\s?==\s?1/, Criteria[j].replace(" = ", " == ").replace("indexOf", ".indexOf").replace("substring", ".substring") + " && 1 == 1");
			}

			Result = /\{[^\]]*\}/i.exec(Func);
			Func = Result[0].replace(" && 1 == 1", "");
			
			var testCriteria = new Function("pNode", "iNode", Func);
		}
		
		return {criteria:testCriteria, path:pPath};
	}
	
	this.getXPathElements = function(xPath)
	{
		var Path = xPath;
		var Next = "";
		var AllNodes = false;
		
		if (xPath.indexOf("/") >= 0)
		{
			Path = xPath.substring(0, xPath.indexOf("/"));
			Next = xPath.substring(Path.length + 1);
			
			if (xPath.indexOf("//") == 0)
			{
				Path = Next.replace("/", "");
				Next = "";
				AllNodes = true;
			}
		}
		
		var Criteria = this.getXPathCriteria(Path);
		
		return {path:Criteria.path, nextPath:Next, all:AllNodes, criteria:Criteria.criteria};
	}
	
	this.getXPathNodes = function(pNewRoot, pPath)
	{
		var pNodes = pNewRoot.childNodes;
		if (pPath.all)
		{
			pNodes = pNewRoot.getElementsByTagName(pPath.path);
		}
		return {nodes:pNodes, length:pNodes.length};
	}
	
	this.isValidTag = function(pCurrNode, pTag)
	{
		return (pCurrNode.tagName == pTag);
	}
	
	this.isValidCriteria = function(pCriteria, pINode, pNode)
	{
		if (pCriteria == null)
		{
			return true;
		}
		else
		{
			var ValidCriteria = pCriteria(pNode, pINode);		
			return ValidCriteria;
		}
	}
	
	this.parse = function(pXPath, pNewRoot)
	{
		pNewRoot = (pNewRoot == null ? pRoot : pNewRoot);

		var xPath = this.getXPathElements(pXPath);
		var pNodes = this.getXPathNodes(pNewRoot, xPath);
		var intNode = 0;
		
		for (var iNode = 0; iNode < pNodes.length; iNode++)
		{
			if (pNodes.nodes[iNode].tagName != undefined)
			{
				intNode += 1;
				var ValidNode = this.isValidTag(pNodes.nodes[iNode], xPath.path);

				if (ValidNode)
				{
					var ValidCriteria = this.isValidCriteria(xPath.criteria, intNode, pNodes.nodes[iNode]);
				
					if (ValidCriteria)
					{
						if (xPath.nextPath == "")
						{
							Nodes.push(new jenaXmlNode(pNodes.nodes[iNode])); 
						}
						else
						{
							this.parse(xPath.nextPath, pNodes.nodes[iNode]); 
						}
					}
				}
			}
		}
		
		return Nodes;
	}
	
	return RetValue;
}

function jenaXml(pXml)
{
	this.xmlDoc = null;	
	var self = this;
	
	this.init = function()
	{
		if (pXml !== null && pXml !== undefined) 
		{
			if (pXml.indexOf("<") === 0)
			{
				this.parse();
			}
			else
			{
				this.load();
			}
		}
	};
	this.parse = function()
	{
		pXml = pXml.replace(/\t/g, "").replace(/\n/g, "");
		if (window.DOMParser)
		{
		  var parser = new DOMParser();
		  this.xmlDoc = parser.parseFromString(pXml, "text/xml");
		}
		else
		{
		  this.xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
		  this.xmlDoc.async = "false";
		  this.xmlDoc.loadXML(pXml);
		}
		
		this.CurrentNode = null;
		return self;
	};
	this.load = function()
	{
		if (window.XMLHttpRequest)
		{
			xml = new window.XMLHttpRequest();
			xml.open("GET", pXml, false);
			xml.send("");
			this.xmlDoc = xml.responseXML;
		}
		else if (ActiveXObject("Microsoft.XMLDOM"))
		{
			xml = new ActiveXObject("Microsoft.XMLDOM");
			xml.async = false;
			xml.load(pXml);
			this.xmlDoc = xml;
		}
		
		return self;
	};
	this.node = function(xPath)
	{
		return this.nodes(xPath)[0];
	};
	this.nodes = function(xPath)
	{
		return jenaXmlParser(this.xmlDoc).parse(xPath);
	};
	this.wrap = function(pNodeName, pNodeValue, pArguments)
	{
		var Attributes = "";
		pNodeValue = pNodeValue || "";
		
		for (var Key in pArguments)
		{
			Attributes += " " + Key + "=\"" + pArguments[Key] + "\"";
		}
		
		var retXml = "<" + pNodeName + Attributes;
		
		if (pNodeValue === "") retXml += "/>";
		else retXml += ">" + pNodeValue + "</" + pNodeName + ">";
		
		return retXml;
	};
	
	this.init();

	return this;
}

var jXml = function(pXmlFileOrData)
{
	return new jenaXml(pXmlFileOrData);
}
