function feed(newUrl, newTargetId) {
	this.http_request = false;
	
	// Make sure the targetId exists.
	if (document.getElementById(newTargetId)==null) {
		window.alert("Feed: Target element doesn't exist: " + newTargetId + " == " + document.getElementById(newTargetId));
		return false;
	}
	this.targetId=newTargetId;
	
	// Make sure the url is not blank.
	if (newUrl=="") {
		this.setMessage("No url passed.");
	}
	this.url=newUrl;
	
	// Set up the timer to use for refreshes
	this.setDelay(5000);
	this.setCyclesPerRefresh(60);
	
	// Attempt to read in the XML
	this.getXML();
		
	// Start the ticker cycling
	this.runCycle();
}

// Overwrites the items list with a single item (allowing error messages etc. to be forced up)
feed.prototype.setMessage = function(message) {
	this.items=new Array();
	this.items[0]=["", message];
	this.refreshDisplay();
}

// Set the delay between cycles - value in milliseconds
feed.prototype.setDelay = function(newDelay) {
	this.timerDelay=newDelay;
}

// Speed up the refreshes by halving the time between them.
feed.prototype.faster = function() {
	this.timerDelay = this.timerDelay / 2;
	this.nextCycle();
}

// Slow down the refreshes by doubling the time between them.
feed.prototype.slower = function() {
	this.timerDelay = this.timerDelay * 2;
	this.nextCycle();
}

// Set the number of cycles that get repeated through before the xml is read again
feed.prototype.setCyclesPerRefresh = function(newCycles) {
	this.cyclesPerRefresh=newCycles;
	this.cycleCounter=0;
}

// Call a timer loop
feed.prototype.nextCycle = function() {
	if (this.timerId!=null) {
		clearTimeout(this.timerId);
	}
	_this=this;
	this.timerId=setTimeout("_this.runCycle()", this.timerDelay);
}

feed.prototype.refreshDisplay = function() {
	// Get the latest message
	newHTML="";
	if (this.items!=null) {
		if (this.items.length!=null) {
			if (this.items.length>0) {
				if (this.cycleCounter==null) {
					this.cycleCounter=0;
				}
				
				thisItem=this.items[this.cycleCounter % (this.items.length)]; // By using mod, it'll keep repeating as it goes off the end of the list
				
				// Build a linked or non linked version depending on whether a url is specified as position 0
				if (thisItem[0]!="") {
					newHTML="<a href='"+thisItem[0]+"'>"+thisItem[1]+"</a>";
				} else {
					newHTML=thisItem[1];
				}
			}
		} else { newHTML=""; }
	} else { newHTML="Items variable missing."; }
	
	// Write the newHTML in to the target element
	fadeIn(this.targetId,0,100,30);
	document.getElementById(this.targetId).innerHTML=newHTML;
}

// Run a single cycle of the ticker
feed.prototype.runCycle = function() {
	// Make certain the timer's been cleared
	if (this.timerId!=null) {
		clearTimeout(this.timerId);
	}
	this.timerId=null;
	
	this.refreshDisplay();
	
	// Increment the counter
	this.cycleCounter++;
	
	// If it's time for an update...
	if (this.cycleCounter >= this.cyclesPerRefresh) {
		// Make the XML call again
		this.getXML();
	}
	
	// Set up a timed call for the next cycle
	this.nextCycle();
}

feed.prototype.getXML = function() {
	this.http_request = false;
	
	if (window.XMLHttpRequest) { // Mozilla, Safari, ...		
		this.http_request = new XMLHttpRequest();
		if (this.http_request.overrideMimeType) {
			this.http_request.overrideMimeType('text/xml');
		}
	} else if (window.ActiveXObject) { // IE
		try {
			this.http_request = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				this.http_request = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {}
		}
	}
	
	if (!this.http_request) {
		this.setMessage("Unable to open AJAX request.");
		return false;
	}

	this.setMessage("Loading...");

	_this=this;
	this.http_request.onreadystatechange = function() { _this.gotXML(); };
	this.http_request.open('GET', this.url, true);
	this.http_request.send(null);
}

feed.prototype.gotXML = function() {
	if (this.http_request.readyState<4) {
		this.setMessage("Loading... ("+(this.http_request.readyState * 25)+"%)");
	} else {
		if ( (this.http_request.status!=0) && (this.http_request.status!=200) ) {
			this.setMessage("There was a problem with the AJAX request ("+this.http_request.status+")");
		} else {
			if (this.http_request.responseXML==null) {
				this.setMessage("Unable to read the XML");
			} else {
				if (!this.http_request.responseXML.hasChildNodes()) {
					this.setMessage("File does not appear to have the text/xml mimetype.");
				} else {
					xmlItems=this.http_request.responseXML.getElementsByTagName("item");
					this.items=new Array();
					
					for (itemCount=0; itemCount<xmlItems.length; itemCount++) {
						thisItemCount=this.items.length;
						thisTitles=(xmlItems[itemCount].getElementsByTagName("title"));
						thisLinks=(xmlItems[itemCount].getElementsByTagName("link"));
						
						if (thisTitles!=null) {
							if (thisTitles.length > 0) {
								this.items[thisItemCount]=new Array();
								this.items[thisItemCount][1]=thisTitles[0].firstChild.nodeValue;
								if (thisLinks!=null) {
									if (thisLinks.length > 0) {
										this.items[thisItemCount][0]=thisLinks[0].firstChild.nodeValue;
									}
								}
							}
						}
					}
					this.cycleCounter=0;
					this.refreshDisplay();
				}
			}
		}
	}
}
