/**
 * @fileOverview This is the AHC namespace making up common methods that can be
 * found throughout many of the AHC's sites including MED.
 * @author <a href="mailto:Nate Sigrist &lt;sigr0005@umn.edu&gt;">Nate Sigrist</a>
 * &nbsp;<a href="http://www.twitter.com/NateSigrist">&#64;NateSigrist</a>
 * @version v0.10 <i>beta</i> 2010.10.07
 */

/** @ignore */
var ahc	= ahc || {};
var AHC = AHC || {};

(function() {
	
	/**
	 * Common methods used through the AHC's (and MED) sits.
	 * @version 0.10 [2010.10.07]
	 * @class
	 */
	ahc.Common					= function() {};

	/**
	 * XPath constants for {@link #.xpathEvaluate}
	 */
	ahc.Common.XPATH			= {
		ANY_TYPE:						0,
		NUMBER_TYPE:					1,
		STRING_TYPE:					2,
		BOOLEAN_TYPE:					3,
		UNORDERED_NODE_ITERATOR_TYPE:	4,
		ORDERED_NODE_ITERATOR_TYPE:		5,
		UNORDERED_NODE_SNAPSHOT_TYPE:	6,
		ORDERED_NODE_SNAPSHOT_TYPE:		7,
		ANY_UNORDERED_NODE_TYPE:		8,
		FIRST_ORDERED_NODE_TYPE:		9
	};
	
	/**
	 * The GET parameters of the current page as name/value pairs.
	 * @type Object
	 */
	ahc.Common.GET				= parseGetParams();
	
	/**
	 * Adds an event listener no matter what browser you are using.  If event is missing as a
	 * parameter such as in IE then an event object is created with the standard properties.
	 * @since version 1
	 * @example AHC.Common.addEventListener(document.getElementsByTagName("body")[0], "load", 
	 * function() {[<i>code</i>]}, false);
	 * @example AHC.Common.addEventListener("anId", "click", function() {[<i>do something</i>]}, false);
	 * @param {DOMElement}	element		The DOM element to add an event listener to.
	 * @param {DOMEvent}	event		The event as a string to listen for.
	 * @param {function}	callback	A function that will be called when the event ocures.
	 * @param {Boolean}		useCapture	if <code>true</code> the event will be fired first before being
	 * passed off to the events below it. If <code>false</code> then the event will follow a "bubble up"
	 * approach.
	 * @see The w3 standard: <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-
	 * EventTarget-addEventListener">addEventListener</a>
	 */
	ahc.Common.addEventListener	= function(element, event, callback, useCapture) {
		if(typeof element === "string") element = document.getElementById(element);
		(function(callback) {
			if(element.addEventListener) element.addEventListener(event, callback, useCapture);
			else element.attachEvent("on"+event, callback);
		})( (!("event" in window))? callback : function() {
				var event			= window.event;
				var preventDefault	= false;
				
				event.currentTarget	= element;
				event.which			= event.keyCode;
				event.preventDefault= function() { event.returnValue = false; preventDefault = true;	};
				
				var returnValue	= callback.call(element, event);
				//alert("return value: " + ((typeof returnValue != 'undefined')? returnValue : !preventDefault));
				return (typeof returnValue != 'undefined')? returnValue : !preventDefault;
			}
		);
	}
	
	//////////////////////////////////////////////////////////////////////////////////////////////////
	// Setup for onReady																			//
	ahc.Common.addEventListener(window, "load", function() { if(!document.readyState) document.readyState = "complete"; }, false);
	/**
	 * Executed whenever the document is done loading regardless if document has already passed the
	 * status change event.
	 */
	ahc.Common.onReady			= function(callback) {
		if(document.readyState !== "complete") {
			if("addEventListener" in window) window.addEventListener("load", callback, false);
			else window.attachEvent("onload", callback);
		} else callback.call();
	};
	
	/**
	 * Serializes an object into a JavaScript Object String (JSON).
	 * @param {Object}	obj	The object to be serialized to a string.
	 * @return {String} The serialized string.
	 */
	ahc.Common.toJson			= function(obj) {
		switch(typeof obj) {
			case "string":	return '"'+obj.replace(/"/g, '\\"')+'"';
			case "object":
				if(obj instanceof Array) {
					var s = "[";
					for(var d=0; d<obj.length; d++) {	// use for(d in obj) loop here :-/
						var j = this.toJson(obj[d]);
						if(j != null) s += j + ",";
					}
					if(s.length !== 1) s = s.substring(0, s.length-1);
					return s + "]";
				} else {
					var s = "{";
					for(d in obj) {
						var j = this.toJson(obj[d]);
						if(j != null) s += '"'+d+'":' + j + ",";
					}
					if(s.length > 1) s = s.substring(0, s.length-1);
					return s + "}";
				}
				break;
			case "function":
				return null;
				break;
			default: return obj;
		}
	};
	
	/*
	 * This is some old code that needs to be cleaned up.
	 */
	
	/**
	 * Gets a new XML object from whatever browser you are using ;-)
	 * @param {String}	text	Some XML as text that is to be used to
	 * generate the new XML object.
	 */
	ahc.Common.xml				= function(text) {
		if("DOMParser" in window) {
			parser			= new DOMParser();
			xmlDoc			= parser.parseFromString(text, "text/xml");
		} else { // Internet Explorer
			xmlDoc			= new ActiveXObject("Microsoft.XMLDOM");
			xmlDoc.async	= "false";
			xmlDoc.loadXML(text);
		}
		return xmlDoc;	
	};
	
	/**
	 * Select the XMLNS to use from the XML document.  This is supposed
	 * to be a security option but I'm not sure just how effective it is
	 * or why it is even considered security.  Also, this is only used in
	 * IE.
	 * @param {XMLDocument}	doc			The XML document to select the
	 * active name spaces.
	 * @param {String}		defaultNS	???
	 */
	ahc.Common.setXMLNS			= function(doc, defaultNS) {
		if("setProperty" in doc) {
			doc.setProperty("SelectionLanguage", "XPath");
			var d	= doc.documentElement;
			var ns	= "";
			for(var i=0; i<d.attributes.length; i++) {
				var xmlns = d.attributes.item(i).nodeName;
				if(xmlns.match(/^xmlns(?::.+)?$/)) {
					if(xmlns.match(/^xmlns$/) && defaultNS) xmlns += ":"+defaultNS;
					ns	+= xmlns + "=\""+d.attributes.item(i).nodeValue+"\" ";
				}
			}
			doc.setProperty("SelectionNamespaces", ns);
		}
	}
	
	/**
	 * Find a node within an XML document using xpath.  This is much easier
	 * than trying to climb the structure looking for matching node types
	 * and tag names!
	 * @param {String}		xpathExpression		The XPath string to use to
	 * try to find a node.
	 * @param {XMLNode}		contextNode			The node to search from as
	 * the "root" of the document.
	 * @param {Function}	namespaceResolver	A function that returns the
	 * matching ...?
	 * @param {Integer}		resultType			Determines what kind of
	 * results this function should return.  See {@link #.XPATH} for the
	 * possible result types and then go to Mozilla's site for a more
	 * detailed explanation.
	 * @param {XPathResult}	result				The results from this method
	 * but the most likely better choice is to set this to null.
	 * @return {XPathResult} The results of the xpath query.
	 * @see ahc.Common.$ for an even easier xpath implementation.
	 * @see ahc.Common.XPATH
	 */
	ahc.Common.xpathEvaluate	= function(xpathExpression, contextNode, namespaceResolver, resultType, result) {
		var doc	= (contextNode.nodeType === 9)? contextNode : contextNode.ownerDocument;
		if(doc.evaluate) return doc.evaluate(xpathExpression, contextNode, namespaceResolver, resultType, result);
		else return {
			nodes:			contextNode.selectNodes(xpathExpression),
			index:			0,
			iterateNext:	function() {
				if(this.index < this.nodes.length) return this.nodes[this.index++]; else return null;
			}
		};
	};

	/**
	 * A simplified solution for getting nodes from an xpath query but
	 * without the various result options.  This method only uses the
	 * {@link #.XPATH.UNORDERED_NODE_SNAPSHOT_TYPE} result type and returns
	 * the results as an array.
	 * @param {String}		xpathExpression		The XPath string to use to
	 * try to find a node.
	 * @param {XMLNode}		contextNode			The node to search from as
	 * the "root" of the document.
	 * @param {Function}	namespaceResolver	A function that returns the
	 * matching ...?
	 * @return {Array} A collection of the nodes found by this xpath query.
	 */
	ahc.Common.$				= function(xpathExpression, contextNode, namespaceResolver) {
		if(!contextNode) contextNode = document;
		var doc	= (contextNode.nodeType === 9)? contextNode : contextNode.ownerDocument;
		
		if(doc.evaluate) {
			var results	= doc.evaluate(xpathExpression, contextNode, namespaceResolver, ahc.Common.XPATH.UNORDERED_NODE_SNAPSHOT_TYPE, null);
			var nodes	= [];
			for(var i=0; i<results.snapshotLength; i++) nodes.push(results.snapshotItem(i));
			return (nodes.length !== 0)? nodes : null;
		} else {
			try{ return contextNode.selectNodes(xpathExpression); } catch(e) { return null; }	// No, I don't care if I mistakenly search for something that is not there IE X(
		}
	};

	/**
	 * An attempt to make construct an object from an object representing
	 * name/value pairing where the result object elements are the names
	 * and their values are the xpaths.  Perhaps not the most simple but
	 * effective.
	 * @param xpaths
	 * @param node
	 * @param ns
	 * @returns {Object} An object representation of this xpath
	 * query.
	 */
	ahc.Common.xpathsToObject	= function(xpaths, node, ns) {
		var results	= {};
		for(var item in xpaths) switch(typeof xpaths[item]) {
			case "string":
				results[item]	= this.$(xpaths[item], node, ns);
	/*			if("console" in window && node.nodeName === "enclosure") {
					console.log("enclosure: %o; xpaths[item]: %o; results[item]: %o", node, xpaths[item], results[item]);
				}
	//*/
				break;
			case "object":
				var r	= [];
				for(var xpath in xpaths[item]) {
					var nodes = this.$(xpath, node, ns);
					
					if(nodes != null) {
						for(var i=0; i<nodes.length; i++)
							r.push(this.xpathsToObject(xpaths[item][xpath], nodes[i], ns));
						results[item]	= r;
					}
				}
				break;
		}
		return results;
	};
	
	/**#@+
	 * @memberOf ahc.Common
	 * @private
	 * @function
	 */
	
	/**
	 * Parses the current page search portion of it's URL for the GET
	 * parameters.
	 * @name parseGetParams
	 * @return {Object} An object with name/value pairs.
	 */
	function parseGetParams() {
		var search	= location.search.match(/\?.*$/);
		var GET		= {};
		if(search == null) return GET;
		
		search	= search[0];
		
		var exps	= search.substring(1,search.length).match(/[^=&]+(?:=[^&]*)?/g);
		for(var i=0; i<exps.length; i++) {
	 		var parts = exps[i].match(/^([^=]+)(?:=(.*))?$/);
	 		GET[unescape(parts[1])] = parts[2]? unescape(parts[2]) : true;
		}
		return GET;
	};
	/**#@-*/
	
	ahc.Common.printContentPageType1 = function() {
		$("#print").remove();
		$("body").append("<div id='print' style='display:none'></div>");
		$("#print").append($("link[type=text/css]").clone()); // grab page's CSS
		$("#print link[type=text/css]").wrapAll("<head/>");
		// Page-specific content
		$("#print").append($(".subContentWithSidebar .subContent").clone());
		$("#print .subContent").css("height","").css("width","100%").wrap('<div class="subContentWithSidebar" />');
		$("#print").find(".subContent > h1").css({"text-align": "center", "color": "#000000", "background-color": "transparent"});
		$("#print .subContentWithSidebar").wrap('<div id="wrapper" />');
		$("#print .subContent").prepend("<img style='display:block; margin-left: auto; margin-right: auto' src='" + $("#printBanner").attr("href") + "' />");
		$("#print .subHead").remove();
		// Finalize
		$("#print .printButton").remove();
		$("#print .externalLink").removeClass("externalLink");
		$("#print").children("#wrapper").wrap("<body/>");
		$("#print head, #print body").wrapAll("<html/>");
		var printWindow = window.open('', '', 'width = 640, height = 480, status = 0, toolbar = 0');
		printWindow.document.write($("#print").html());
		printWindow.document.close();
		printWindow.focus();
		$("#print").remove();
		printWindow.print();
		return false;
	}
	
	ahc.Common.printContentPageType2 = function() {
		$("#print").remove();
		$("body").append("<div id='print' style='display:none'></div>");
		$("#print").append($("link[type=text/css]").clone()); // grab page's CSS
		$("#print link[type=text/css]").wrapAll("<head/>");
		// Page-specific content
		$("#print").append($(".mainContentWithSidebar .mainContent").clone());
		$("#print").find(".mainContent > h1").css({"text-align": "center", "color": "#000000", "background-color": "transparent"});
		$("#print .mainContent").css("height","").css("width","100%").wrap('<div class="mainContentWithSidebar" />');
		$("#print .mainContentWithSidebar").wrap('<div id="wrapper" />');
		$("#print .mainContent").prepend("<img style='display:block; margin-left: auto; margin-right: auto' src='" + $("#printBanner").attr("href") + "' />");
		$("#print .hWidgits").remove();
		$("#print .subHead").remove();
		// Finalize
		$("#print .printButton").remove();
		$("#print .externalLink").removeClass("externalLink");
		$("#print").children("#wrapper").wrap("<body/>");
		$("#print head, #print body").wrapAll("<html/>");
		var printWindow = window.open('', '', 'width = 640, height = 480, status = 0, toolbar = 0');
		printWindow.document.write($("#print").html());
		printWindow.document.close();
		printWindow.focus();
		$("#print").remove();
		printWindow.print();
		return false;
	}
	
	ahc.Common.printListPage = function() {
		$("#print").remove();
		$("body").append("<div id='print' style='display:none'></div>");
		$("#print").append($("link[type=text/css]").clone()); // grab page's CSS
		$("#print link[type=text/css]").wrapAll("<head/>");
		// Page-specific content
		$(".readMore:even").not($(".viewMore .readMore")).click(); 
		$("#print").append($(".mainContentWithSidebar .mainContent").clone());
		$("#print").find(".mainContent > h1").css({"text-align": "center", "color": "#000000", "background-color": "transparent"}).detach().prependTo($("#print .mainContentPad"));
		$("#print .mainContent").wrap('<div class="mainContentWithSidebar" />');
		$("#print .mainContentWithSidebar").wrap('<div id="wrapper" />');
		$("#print .readMore, #print img, #print .storyImage, #print .titleBar").remove();
		$("#print .stories .content").each(function() {
			$(this).css("height", parseInt($(this).css("height")) - 200 + "px");
		});
		$("#print .mainContentPad").prepend("<img style='display:block; margin-left: auto; margin-right: auto' src='" + $("#printBanner").attr("href") + "' />");
		$(".readMore:even").click(); 
		// Finalize
		$("#print .printButton").remove();
		$("#print .externalLink").removeClass("externalLink");
		$("#print").children("#wrapper").wrap("<body/>");
		$("#print head, #print body").wrapAll("<html/>");
		var printWindow = window.open('', '', 'width = 640, height = 480, status = 0, toolbar = 0');
		printWindow.document.write($("#print").html());
		printWindow.document.close();
		printWindow.focus();
		$("#print").remove();
		printWindow.print();
		return false;
	}
	
})();

