// create namespaces
if (!AP)
	var AP = new Object();
	
if (!AP.UI)
	AP.UI = new Object();
	
if (!AP.Utils)
  AP.Utils = new Object();

AP.Utils.HTTP = new Object();

// creates a scrolling ticker either from rss documents specified by urls, or 
// scrolls existing content by the id of that content's node
AP.UI.Ticker = function(nodeId, contentNodeId, /*optional*/rssUrls, /*optional*/delta, /*optional*/delay) {
	this.parent = document.getElementById(nodeId);
	this.parent.style.overflow = "hidden";
	this.parent.style.whiteSpace = "nowrap";
	
	this.content = document.getElementById(contentNodeId);
	this.content.style.display = "inline";
		
	this.templateHtml = null;
	
	this.delta = delta != null ? delta : -4;
	this.delay = delay != null ? delay : 100;
		
	if (rssUrls != null) {
		// remember and clear HTML to be used as template
		this.templateHtml = this.content.innerHTML;
		this.content.innerHTML = "";
		
		for (var i=0; i<rssUrls.length; i++) {
			new AP.Utils.RssDocument(rssUrls[i], this, this.RssLoad);
		}
	}
	
	this.Start();
}

AP.UI.Ticker.prototype.Start = function() {

	// This works for FF but not for IE.
	// Specifically, you set this.content.style.left to some value and nothing happens.
	this.content.style.left = this.parent.offsetWidth + "px";

	var self = this;
	
	this.timerId = setInterval(function() { self.DoScroll(); }, this.delay);
	this.content.onmouseover = function() { self.Pause(); };
	this.content.onmouseout = function() { self.Resume(); };
}

AP.UI.Ticker.prototype.DoScroll = function() {

	// This conditional is for IE and it is here because IE will not return a proper offsetWidth if I place it anywhere else.
	if (this.content.width == 0) {
		this.content.width = this.content.offsetWidth;
		
		// I'm sneaking this in here because at this point IE decides to behave.
		// I'm counting on the fact that this conditional will only be true for IE and will only be true once.
		this.content.style.left = this.parent.offsetWidth + "px";
	}

	var newLeft = this.content.offsetLeft + this.delta;
	
	//window.status = "newLeft: " + newLeft + " this.content.width: " + this.content.width;
	
	if (-newLeft > this.content.width) {
		newLeft = this.parent.offsetWidth;
	}
	
	this.content.style.left = newLeft + "px";
}

AP.UI.Ticker.prototype.RssLoad = function(rssDoc) {
	var html = "";
	
	for (var i=0; i<rssDoc.items.length; i++)
		html += this.templateHtml.replace(/__TITLE__/g, rssDoc.items[i].title).replace(/__LINK__/g, rssDoc.items[i].link).replace(/__DESCRIPTION__/g, rssDoc.items[i].description).replace(/__PUBDATE__/g, rssDoc.items[i].pubDate).replace(/__AUTHOR__/g, rssDoc.items[i].author).replace(/__GUID__/g, rssDoc.items[i].guid);

	this.content.innerHTML += html;
	
	// This is my solution to the problem regarding FF and block elements,
	// namely, that FF will not return a proper offsetWidth for a block element.
	// So I populate an inline element, get its offsetWidth, and then turn it into a block element.
	// It should make everyone happy but for some reason IE is not cool with this.
	// To get around IE I have an additional conditional later on.
	this.content.width = this.content.offsetWidth;
	this.content.style.display = "block";
	this.content.style.position = "relative";
}

AP.UI.Ticker.prototype.Pause = function() {
	clearInterval(this.timerId);
}

AP.UI.Ticker.prototype.Resume = function() {
	var self = this;
	
	this.timerId = setInterval(function() { self.DoScroll(); }, this.delay);
}

// highlightes all elements identified by name and gets source code from specified property
AP.Utils.RssDocument = function(url, caller, onLoadCallback) {
	this.caller = caller;
	this.onLoadCallback = onLoadCallback;
	
	this.title = null;
	this.link = null;
	this.description = null;
	this.copyright = null;
	this.items = new Array();
	
	AP.Utils.HTTP.Get(url, this, this.Load);
}

AP.Utils.RssDocument.prototype.Load = function(response) {

	if (response.status == 200) {
		//TODO: ensure at least one child
		var channel = response.responseXML.getElementsByTagName("rss")[0];
		
		this.title = getElement(channel, "title");
		this.link = getElement(channel, "link");
		this.description = getElement(channel, "description");
		this.copyright = getElement(channel, "copyright");
		
		var items = channel.getElementsByTagName("item");
		
		for (var i=0; i<items.length; i++) {
			this.items[i] = new Object();
			
			this.items[i].title = getElement(items[i], "title");
			this.items[i].link = getElement(items[i], "link");
			this.items[i].description = getElement(items[i], "description");
			this.items[i].pubDate = getElement(items[i], "pubDate");
			this.items[i].author = getElement(items[i], "author");
			this.items[i].guid = getElement(items[i], "guid");
		}
		
		if (this.caller != null && this.onLoadCallback != null)
			this.onLoadCallback.call(this.caller, this);
	}

	function getElement(parent, elementName) {
	
		try {
			return parent.getElementsByTagName(elementName)[0].firstChild.nodeValue;
		}
		catch(e) {
			return null;
		}
	}
}

AP.Utils.RssDocument.prototype.toString = function() {
	return this.title + "\n" + this.description + "\n" + this.link + "\n" + this.copyright + "\n" + this.items.length + " items";
}

AP.Utils.HTTP.Get = function(url, caller, successFunc) {
	var www;
	
	// for IE
	if (typeof ActiveXObject != "undefined")
		www = new ActiveXObject("Microsoft.XMLHTTP");
	// for W3C
	else if (typeof XMLHttpRequest != "undefined")
		www = new XMLHttpRequest();
	else {
		alert("This browser is not supported.");
		return null;
	}
	//alert("in");
	www.onreadystatechange = function() {
		AP.Utils.HTTP.HttpStateChange(www, caller, successFunc);
	};
	
	//alert("HTTP GET Before");
	www.open("GET", url, true);
	//alert("HTTP GET AFTER");
	www.send(null);
	//alert("out");
}

AP.Utils.HTTP.HttpStateChange = function(www, caller, successFunc) {
	// if completed
	if (www.readyState == 4) {
		// call the succes function back in the context/scope of the original caller
		successFunc.call(caller, www);
	}
}
