/* jQuery XML Plugin */
/* Last modified: 7/11/2008 */
(function($){
	
	/* PRIVATE */
	
	// expression cache
	var xPathCache = [];
	
	// serialize namespaces:
	// used in IE as well as W3C to generate expression IDs
	var serializeNS = function(namespaces) {
		var s = [];
		for (var key in namespaces) {
			s.push('xmlns:' + key + '="' + namespaces[key] + '"');
		}
		return s.join(" ");
	}
	
	// creates a query, pulling from cache if available
	var getXPathExp = function (query, namespaces) {		
		var id = query + serializeNS(namespaces);
		
		// check cache first
		if (xPathCache[id]) { 
			return xPathCache[id];
		}
		
		// create expression
		var exp = document.createExpression(
			query,
			function(prefix) {
				return namespaces[prefix];
			}
		);
		
		// cache and return
		xPathCache[id] = exp;
		return exp;
	}
	
	// Finds a prefix for a given namespace URI 
	var getNSPrefixIE = function (NSURI, contextEl, omitColon) {
		var NSPrefix = "";
		var docEl = (contextEl.ownerDocument) ? contextEl.ownerDocument.documentElement : contextEl.documentElement;
		
		// search for namespace attributes in the document element
		for (var i = 0, attrs = docEl.attributes, attrLength = attrs.length; i < attrLength; i++) {
			
			// we found our namespace
			if (attrs[i].nodeValue == NSURI && attrs[i].nodeName.indexOf("xmlns") != -1) {
			
				// grab prefix if there is one
				if (attrs[i].nodeName.indexOf(":") != -1) {
					NSPrefix = attrs[i].nodeName.split(":")[1];
					if (!omitColon) {
						NSPrefix += ":";
					}
				}
				break;
			}
		}
		return NSPrefix;
	};
	
	// retrieve an attribute with a given namespace
	var getAttrNS = function (NSURI, contextEl, attrName) {
		return (document.getAttributeNS) 
			? contextEl.getAttributeNS(NSURI, attrName) // W3C DOM Level 2
			: contextEl.getAttribute(getNSPrefixIE(NSURI, contextEl) + attrName); // IE Hack
	};
	
	// set an attribute with a given namespace
	var setAttrNS = function (NSURI, contextEl, attrName, val) {
		return (document.setAttributeNS)
			? contextEl.setAttributeNS(NSURI, attrName, val) // W3C DOM Level 2
			: contextEl.setAttribute(getNSPrefixIE(NSURI, contextEl) + attrName, val); // IE Hack
	};
	
	/* PUBLIC */
	
	// serialize: returns a serialized string of xml
	// not chainable
	$.fn.serializeXML = function () {
		var target = this.get(0);
		return (typeof XMLSerializer != "undefined") ? (new XMLSerializer()).serializeToString(target) : target.xml;
	};
		
	// tagsNS: generic tag name NS selector
	// tagName is the local name!
	// chainable
	$.fn.tagsNS = function (tagName, NSURI) {
		var results = [];
		this.each(function(){
			var curRes = (document.getElementsByTagNameNS) 
				? this.getElementsByTagNameNS(NSURI, tagName) 
				: this.getElementsByTagName(getNSPrefixIE(NSURI, this) + tagName);
			results = results.concat($.makeArray(curRes));
		});
		return $(results);
	};
		
	// attrNS: get or set attributes on first selected element based on namespace
	// name is the local name!
	// attrNS(name, NSURI) : get
	// attrNS(properties, NSURI) : set multiple namespaced attributes
	// attrNS(name, value, NSURI) : set to string
	// attrNS(name, function, NSURI) : set to executed function
	// last 
	$.fn.attrNS = function () {
		var args = $.makeArray(arguments);
	
		// we'll use the same criteria jQuery does to see whether to 
		// get or set the attributes
		
		// if two arguments and first is string, get. . . 
		if (args.length == 2 && typeof args[0] == "string") {
			return getAttrNS(args[1], this.get(0), attrName);
		}
		
		// . . . otherwise, set
		if (typeof args[0] == "string") {
			var attrs = {};
			attrs[args[0]] = args[1];
		}
		else {
			var attrs = args[0];
		}
		var NSURI = args[args.length - 1];
		this.each(function(){
			for (var key in attrs) {
				setAttrNS(NSURI, this, key, attrs[key]);
			}
		});
	};
		
	// xPath: returns the results of an xPath query
	// performed on each element
	// chainable
	/*
	$.fn.xml.XPath = function (query) {
		var results = [];
		
		// TODO: NEED TO CREATE A FUNCTION THAT CAN RETRIEVE A HASH OF NAMESPACE PREFIXES AND URLS
		var namespaces = 
		
		// W3C
		if (document.createExpression) {
			var exp = getXPathExp(query, namespaces);
			this.each(function(){
				var snapshots = exp.evaluate(this, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
				for (var i = 0; i < snapshots.snapshotLength; i++) {
					results.push(snapshots[i]);
				}
			});
		}
		
		// IE
		else {
			this.each(function(){
				var target = this;
				
				// grab the document element
				var doc = (target.ownerDocument) ? target.ownerDocument : target;
				
				// make sure we're not using the document element here
				target = (target == doc) ? target.documentElement : target;
				
				// set prefix mappings
				doc.setProperty("SelectionLanguage", "XPath");
				doc.setProperty("SelectionNamespaces", serializeNS(namespaces));
				
				results.concat(target.selectNodes(query));
			}
		}
		
		return $(results);
	};
	*/
})(jQuery);
