//rss.js
//an RSS 2.0 reader
//thank to the following:
// http://blogs.law.harvard.edu/tech/rss
// http://www.xml.com/pub/a/2005/02/09/xml-http-request.html
// http://www.adaptivepath.com/publications/essays/archives/000385.php

function RssItem() {
	this.title = null;
	this.link = null;
	this.description = null;
	this.author = null;
	this.category = null;
	this.comments = null;
	this.enclosure = null;
	this.guid = null;
	this.pubDate = null;
	this.source = null;

	this.toString = function() {
		var s = "";
		s += "\n<item>";
		if (this.title != null) {
			s += "\n<title>"+this.title.toString()+"</title>";
		}
		if (this.link != null) {
			s += "\n<link>"+this.link.toString()+"</link>";
		}
		if (this.description != null) {
			s += "\n<description>"+this.description.toString()+"</description>";
		}
		if (this.author != null) {
			s += "\n<author>"+this.author.toString()+"</author>";
		}
		if (this.category != null) {
			s += this.category.toString();
		}
		if (this.comments != null) {
			s += "\n<comments>"+this.comments.toString()+"</comments>";
		}
		if (this.enclosure != null) {
			s += "\n<enclosure>"+this.enclosure.toString()+"</enclosure>";
		}
		if (this.guid != null) {
			s += this.guid.toString();
		}
		if (this.pubDate != null) {
			s += "\n<pubDate>"+this.pubDate.toString()+"</pubDate>";
		}
		if (this.source != null) {
			s += "\n<source>"+this.source.toString()+"</source>";
		}
		s += "\n</item>";
		return s;
	}

}

function RssImage() {
	this.url = null;
	this.title = null;
	this.link = null;
	this.width = null;
	this.height = null;
	this.description = null;

	this.toString = function() {
		var s = "";
		s += "\n<image>";
		if (this.url != null) {
			s += "\n<url>"+this.url.toString()+"</url>";
		}
		if (this.title != null) {
			s += "\n<title>"+this.title.toString()+"</title>";
		}
		if (this.link != null) {
			s += "\n<link>"+this.link.toString()+"</link>";
		}
		if (this.width != null) {
			s += "\n<width>"+this.width.toString()+"</width>";
		}
		if (this.height != null) {
			s += "\n<height>"+this.height.toString()+"</height>";
		}
		if (this.description != null) {
			s += "\n<description>"+this.description.toString()+"</description>";
		}
		s += "\n</image>";
		return s;
	}
	
}

function RssCloud() {
	this.domain = null;
	this.port = null;
	this.path = null;
	this.registerProcedure = null;
	this.protocol = null;

	this.toString = function() {
		var s = "";
		s += "\n<cloud>";
		if (this.domain != null) {
			s += this.domain.toString();
		}
		if (this.port != null) {
			s += this.port.toString();
		}
		if (this.path != null) {
			s += this.path.toString();
		}
		if (this.registerProcedure != null) {
			s += this.registerProcedure.toString();
		}
		if (this.protocol != null) {
			s += this.protocol.toString();
		}
		s += "</cloud>";
		return s;
	}

}

function RssTextInput() {
	this.title = null;
	this.description = null;
	this.name = null;
	this.link = null;

	this.toString = function() {
		var s = "";
		s += "\n<textInput>";
		if (this.title != null) {
			s += this.title.toString();
		}
		if (this.description != null) {
			s += this.description.toString();
		}
		if (this.name != null) {
			s += this.name.toString();
		}
		if (this.link != null) {
			s += this.link.toString();
		}
		s += "</textInput>";
		return s;
	}

}

function RssCategory() {
	this.text = null;
	this.domain = null;

	this.toString = function() {
		var s = "";
		s += "<category";
		if (this.domain != null) {
			s += ' domain="'+this.domain+'"';
		}
		s += ">";
		s += this.text.toString();
		s += "</category>";
		return s;
	}

}

function RssGuid() {
	this.text = null;
	this.isPermaLink = true;

	this.toString = function() {
		var s = "";
		s += "<guid";
		//s += ' isPermaLink='isPermaLink?"true":"false";
		s += " isPermaLink=";
		if (this.isPermaLink) {
			s += '"true"';
		} else {
			s += '"false"';
		}
		s += ">";
		s += this.text.toString();
		s += "</guid>";
		return s;
	}

}

function Rss() {
	var ths = new Object();

	ths.doc = null;
	ths.onload = null;
	ths.onerror = null;
	ths.url = null;
	ths.req = null;

	ths.version = null;
	ths.encoding = null;
	
	ths.title = null;
	ths.link = null;
	ths.description = null;
	
	ths.language = null;
	ths.copyright = null;
	ths.managingEditor = null;
	ths.webMaster = null;
	ths.pubDate  = null;
	ths.lastBuildDate = null;
	ths.category = null;
	ths.generator = null;
	ths.docs = null;
	ths.cloud = null;
	ths.ttl = null;
	ths.image = null;
	ths.rating = null;
	ths.textInput = null;
	ths.skipHours = null;
	ths.skipDays = null;

	ths.items = new Array();

	
	/* Private Methods
	---------------------------*/
	//ths.onXmlLoad = function () {
	function onXmlLoad(req) {

		var rssNode = req.responseXML.documentElement;
		ths.version = rssNode.getAttribute("version").value;
		//ths.encoding = "";

		var channelNode = getChildNode(rssNode,"channel");

		//get required channel elements		
		ths.title = getNodeText(channelNode, "title");
		ths.link = getNodeText(channelNode, "link");
		ths.description = getNodeText(channelNode, "description");

		//get optional channel elements		
		ths.language = tryGetNodeText(channelNode, "language");
		ths.copyright = tryGetNodeText(channelNode, "copyright");
		ths.managingEditor = tryGetNodeText(channelNode, "managingEditor");
		ths.webMaster = tryGetNodeText(channelNode, "webMaster");
		ths.pubDate = tryGetNodeText(channelNode, "pubDate");
		ths.lastBuildDate = tryGetNodeText(channelNode, "lastBuildDate");
		ths.generator = tryGetNodeText(channelNode, "generator");
		ths.docs = tryGetNodeText(channelNode, "docs");
		ths.ttl = tryGetNodeText(channelNode, "ttl");
		ths.rating = tryGetNodeText(channelNode, "rating");
		ths.skipHours = tryGetNodeText(channelNode, "skipHours");
		ths.skipDays = tryGetNodeText(channelNode, "skipDays");
		
		try {
			var categoryNode = getChildNode(channelNode,"category");
			ths.category = new RssCategory();
			try{ths.category.domain = categoryNode.getAttribute("domain").value;} catch(e1) {}
			if (categoryNode.textContent) {
				ths.category.text = categoryNode.textContent;
			} else {
				ths.category.text = categoryNode.text;
			}
		}
		catch(e) {
			ths.category = null;
		}

		try {
			var cloudNode = getChildNode(channelNode,"cloud");
			ths.cloud = new RssCloud();
			ths.cloud.domain = cloudNode.getAttribute("domain").value;
			ths.cloud.port = cloudNode.getAttribute("port").value;
			ths.cloud.path = cloudNode.getAttribute("path").value;
			ths.cloud.registerProcedure = cloudNode.getAttribute("registerProcedure").value;
			ths.cloud.protocol = cloudNode.getAttribute("protocol").value;
		}
		catch(e) {
			ths.cloud = null;
		}
		
		try {
			var imageNode = getChildNode(channelNode,"image");
			ths.image = new RssImage();
			ths.image.url = tryGetNodeText(imageNode, "url");
			ths.image.title = tryGetNodeText(imageNode, "title");
			ths.image.link = tryGetNodeText(imageNode, "link");
			ths.image.width = tryGetNodeText(imageNode, "width");
			ths.image.height = tryGetNodeText(imageNode, "height");
			ths.image.description = tryGetNodeText(imageNode, "description");
		}
		catch(e) {
			ths.image = null;
		}

		try {
			var textInputNode = getChildNode(channelNode,"textInput");
			ths.textInput = new RssTextInput();
			ths.textInput.title = getNodeText(textInputNode, "title");
			ths.textInput.description = getNodeText(textInputNode, "description");
			ths.textInput.name = getNodeText(textInputNode, "name");
			ths.textInput.link = getNodeText(textInputNode, "link");
		}
		catch(e) {
			ths.textInput = null;
		}


		//now get the items
		var items = channelNode.getElementsByTagName("item");
		var item;
		for (var i=0;i<items.length;i++) {
			item = new RssItem();
			//all item elements are optional
			item.title = tryGetNodeText(items[i], "title");
			item.link = tryGetNodeText(items[i], "link");
			item.description = tryGetNodeText(items[i], "description");
			item.author = tryGetNodeText(items[i], "author");
			item.comments = tryGetNodeText(items[i], "comments");
			item.enclosure = tryGetNodeText(items[i], "enclosure");
			item.pubDate = tryGetNodeText(items[i], "pubDate");
			item.source = tryGetNodeText(items[i], "source");

			try {
				var guidNode = getChildNode(items[i],"guid");
				item.guid = new RssGuid();
				try{item.guid.isPermaLink = guidNode.getAttribute("isPermaLink").value;} catch(e1) {}
				if (guidNode.textContent) {
					item.guid.text = guidNode.textContent;
				} else {
					item.guid.text = guidNode.text;
				}
			}
			catch(e) {
				item.guid = null;
			}

			//item.category = tryGetNodeText(items[i], "category");
			try {
				var categoryNode = getChildNode(items[i],"category");
				item.category = new RssCategory();
				try{item.category.domain = categoryNode.getAttribute("domain").value;} catch(e1) {}
				if (categoryNode.textContent) {
					item.category.text = categoryNode.textContent;
				} else {
					item.category.text = categoryNode.text;
				}
			}
			catch(e) {
				item.category = null;
			}


			ths.items[ths.items.length] = item;
		}

		if (ths.onload) {
			ths.onload(ths);
		}
		
	}
	
	function onError(req) {
		if (ths.onerror) {
			ths.onerror(ths);
		}
	}

	function getChildNode(node, name) {
		for (var i=0;i<node.childNodes.length;i++) {
			if (node.childNodes[i].nodeName == name) {
				return node.childNodes[i];
			}
		}
		throw "Node "+name+" is not a child node of "+node.nodeName;
	}


	function tryGetNodeText(node, name) {
		try {
			return getNodeText(node, name)
		}
		catch(e) {
			return null;
		}
	}

/*
	function getNodeText(node, name) {
		return getInnerText(getChildNode(node,name));
	}
	function getInnerText (node) {
		if (node.textContent) {
			return node.textContent;
		} else if (node.text) {
			return node.text;
		} else if (node.innerText) {
			return node.innerText;
		} else {
			switch (node.nodeType) {
			case 3:
			case 4:
				return node.nodeValue;
				break;
			case 1:
			case 11:
				var innerText = '';
				for (var i = 0; i < node.childNodes.length; i++) {
					innerText += getInnerText(node.childNodes[i]);
				}
				return innerText;
				break;
			default:
				return '';
			}
		}
	}
*/

	/* Public Methods
	---------------------------*/
	
	ths.load = function (url) {
		if (url != undefined) {
			ths.url = url;
		}

		ajax.load(ths.url);

		/*		
		if (window.XMLHttpRequest || window.ActiveXObject) {
			ths.doc.open("GET", ths.url, true);
			ths.doc.send(null);
		} else {
			ths.doc.load(ths.url);
		}
		*/
		
	}

	ths.toString = function() {
		var s = "";
		s += '<?xml version="1.0" ?>'; //TODO: add encoding
		s += '\n<rss version="'+ths.version+'">';
		s += "\n<channel>";
		if (ths.title != null) {
			s += "\n<title>"+ths.title.toString()+"</title>";
		}
		if (ths.link != null) {
			s += "\n<link>"+ths.link.toString()+"</link>";
		}
		if (ths.description != null) {
			s += "\n<description>"+ths.description.toString()+"</description>";
		}
		if (ths.language != null) {
			s += "\n<language>"+ths.language.toString()+"</language>";
		}
		if (ths.copyright != null) {
			s += "\n<copyright>"+ths.copyright.toString()+"</copyright>";
		}
		if (ths.managingEditor != null) {
			s += "\n<managingEditor>"+ths.managingEditor.toString()+"</managingEditor>";
		}
		if (ths.webMaster != null) {
			s += "\n<webMaster>"+ths.webMaster.toString()+"</webMaster>";
		}
		if (ths.pubDate != null) {
			s += "\n<pubDate>"+ths.pubDate.toString()+"</pubDate>";
		}
		if (ths.lastBuildDate != null) {
			s += "\n<lastBuildDate>"+ths.lastBuildDate.toString()+"</lastBuildDate>";
		}
		if (ths.generator != null) {
			s += "\n<generator>"+ths.generator.toString()+"</generator>";
		}
		if (ths.docs != null) {
			s += "\n<docs>"+ths.docs.toString()+"</docs>";
		}
		if (ths.ttl != null) {
			s += "\n<ttl>"+ths.ttl.toString()+"</ttl>";
		}
		if (ths.rating != null) {
			s += "\n<rating>"+ths.rating.toString()+"</rating>";
		}
		if (ths.skipHours != null) {
			s += "\n<skipHours>"+ths.skipHours.toString()+"</skipHours>";
		}
		if (ths.skipDays != null) {
			s += "\n<skipDays>"+ths.skipDays.toString()+"</skipDays>";
		}
		if (ths.category != null) {
			s += ths.category.toString();
		}
		if (ths.cloud != null) {
			s += ths.cloud.toString();
		}
		if (ths.image != null) {
			s += ths.image.toString();
		}
		if (ths.textInput != null) {
			s += ths.textInput.toString();
		}

		for (var i=0;i<ths.items.length;i++) {
			s += ths.items[i].toString();
		}		
		
	
		s += "\n</channel>";
		s += "\n</rss>";
		return s;
	}








	/* Constructor
	---------------------------*/
	
	ajax = new Ajax();
	ajax.onload = onXmlLoad;
	ajax.onerror = onError;
	//ajax.onerror = AjaxError;

	
	ths.req = ajax.req;
/*
	if (window.XMLHttpRequest) {
		ths.doc = new XMLHttpRequest();
		ths.doc.onreadystatechange = function () {
			if (ths.doc.readyState == 4) {
				if (ths.doc.status == 200) {
					onXmlLoad();
				} else {
					if (ths.onerror) {
						ths.onerror(ths);
					}
				}
			}
		};

	} else if (window.ActiveXObject) {
		var ARR_ACTIVEX = ["Microsoft.XMLHTTP","MSXML2.DOMDocument.7.0","MSXML2.DOMDocument.6.0","MSXML2.DOMDocument.5.0","MSXML2.DOMDocument.4.0","MSXML2.DOMDocument","MSXML.DOMDocument","Microsoft.XmlDom"];
		for (var s in ARR_ACTIVEX) {
			try {
				ths.doc = new ActiveXObject(ARR_ACTIVEX[s]);
				break;
			}
			catch (e) {
			}
		}
		//if we didn't find the string, send an error
		if (ths.doc == null) {
			throw "MSXML not found on your computer.";
		}
		//ths.doc.onreadystatechange = onreadyhack;
		ths.doc.onreadystatechange = function () {
			if (ths.doc.readyState == 4) {onXmlLoad();}
		};

	} else if (document.implementation && document.implementation.createDocument) {
		ths.doc = document.implementation.createDocument("", "", null);
		ths.doc.onload = onXmlLoad;

 	} else {
		throw "Your browser can't handle this script";
	}
*/

	return ths;
}
