/**
 * RSS Feed Parser and Displayer
 * @author Louis V. Lattanzio
 * 
 * This JS code was written with the help of various other people
 * through Google searches for AJAX and XMLHttpRequest. Feel free to use it.
 * 
 * The end disply of the feed is determined in the BuildData function.
 */


/**
 * This function is used as an entry point to load an RSS feed into a specified <div>
 * It gets an XMLHttpRequest object and passes it to the LoadRSS function.
 * @param divId The id of the <div> in which to insert the RSS feed data
 * @param inputFile The path of the RSS feed
 */
function initRSS(divId, inputFile)
{
	var div = divId;
	var input = inputFile;
	var updateInterval = 900000;

	var rssRequestObject = getXMLHttpRequest();

	var sourceFile = inputFile;

	window.setInterval(function(){LoadRSS(divId, rssRequestObject,sourceFile,updateInterval)},updateInterval);

	LoadRSS(divId, rssRequestObject, sourceFile, updateInterval);
}

/**
 * This function instantiates and returns a browser-specific XMLHttpRequest object
 */
function getXMLHttpRequest()
{
	var xmlHttpObj = false;

	//	Firefox, Safari, etc.
	if (window.XMLHttpRequest)
	{
		xmlHttpObj = new XMLHttpRequest();
	}
	//	Internet Explorer
	else if (window.ActiveXObject)
	{
		xmlHttpObj = new ActiveXObject("Microsoft.XMLHTTP");
	}

	return xmlHttpObj;
}

/**
 * This function loads RSS data using an XMLHttpRequest and specifies the onreadystatechange function
 * @param divId The id of the <div> in which to insert the RSS feed data
 * @param rssRequestObject The XMLHttpRequest object
 * @param sourceFile The path of the RSS feed
 */
function LoadRSS(divId, rssRequestObject, sourceFile, updateInterval)
{
	//	open the connection to the source file
	rssRequestObject.open("GET", sourceFile, true);
	//	set the function to execute when the ready state changes
	rssRequestObject.onreadystatechange = function(){BuildData(divId, rssRequestObject, updateInterval)};
	//	close the connection
	rssRequestObject.send(null);
}

/**
 * This function parses the RSS XML data and formats it for display
 * @param divId The id of the <div> in which to insert the RSS feed data
 * @param rssRequestObject The XMLHttpRequest object
 */
function BuildData(divId, rssRequestObject, updateInterval)
{
	//	Data received successfully
	if (rssRequestObject.readyState == 4)
	{
		//	Data is valid
		if (rssRequestObject.responseText.indexOf('invalid') == -1)
		{
			//	Get the document root node
			var rootNode = rssRequestObject.responseXML.documentElement;

			//	Get the Channel information
			var channel = rootNode.getElementsByTagName('channel').item(0);
			var channelTitle = channel.getElementsByTagName('title').item(0).firstChild.data;
			var link = channel.getElementsByTagName('link').item(0).firstChild.data;

			//htmlOutput = '<h3><a href="'+link+'">'+title+'</a></h3>';

			var items = channel.getElementsByTagName('item');
			//htmlOutput += '<ul>';
			htmlOutput = '<table style="font-family:arial;font-size:10pt;color:#666666;">';
			var rssItems = new Array();
			for (var i=0; i<items.length; i++)
			{
				var item = items[i];

				//var title = item.getElementsByTagName('title').item(0).firstChild.data;
				var title = getTagValue(item, 'title');

				//var description = item.getElementsByTagName('description').item(0).firstChild.data;
				var description = getTagValue(item, 'description');

				//var pubDate = item.getElementsByTagName('pubDate').item(0).firstChild.data;
				var pubDate = getTagValue(item, 'pubDate');
				mRSSDate = parseDate(pubDate);
				pubDate = formatDate(mRSSDate);

				var link = item.getElementsByTagName('link').item(0).firstChild.data;
				var link = getTagValue(item, 'link');

				var rssItem = new RSSItem(title,description,pubDate,link,getJsDate(mRSSDate));
				rssItems[i] = rssItem;
			}

			document.getElementById(divId).innerHTML = getHtmlTableOutput(divId,sortRSSItems(rssItems),updateInterval,channelTitle);
		}
		//else
		//{
		//	alert('invalid data received');
		//}
	}
	//else
	//{
	//	alert('error retrieving data');
	//}
}

function getTagValue(item, tagName)
{
	try{
	return item.getElementsByTagName(tagName).item(0).firstChild.data;
	}
	catch(err)
	{
	return '';}
}

/**
 * This function bubble sorts an Array of RSSItem objects in descending order
 * @param rssItems The Array of RSSItem objects to sort
 * @return mItems The sorted Array of RSSItem objects
 */
function sortRSSItems(rssItems)
{
	var mItems = rssItems;
	var n = mItems.length;

	do
	{
		swapped = false;
		n = n - 1;
		for(var i=0; i<n; i++)
		{
			if ( mItems[i].getJsDate() < mItems[i+1].getJsDate() )
			{
				var tmp = mItems[i];
				mItems[i] = mItems[i+1];
				mItems[i+1] = tmp;
				swapped = true;
			}
		}
	}
	while(swapped);

	return mItems;
}

/**
 * This function gets HTML <table> output for the RSS feed
 * @param divId The id of the <div> in which to insert the RSS feed data
 * @param rssItems An array of RSSItem objects
 * @return htmlOutput The HTML <table> markup for the RSS feed
 */
function getHtmlTableOutput(divId,rssItems,updateInterval,channeltitle)
{
	var htmlOutput = '';

	htmlOutput += '<div style="text-align:center;font-family:arial;font-size:10pt;color:#666666;font-weight:bold;">'+channeltitle+'</a></div>';
	htmlOutput += '<div style="border:1px solid #666666;">';
	htmlOutput += '<table style="font-family:arial;font-size:10pt;color:#666666;width:100%">';

	for (var i=0; i<rssItems.length; i++)
	{
		var item = rssItems[i];

		//htmlOutput += '<a name="'+divId+'"></a>';
		htmlOutput += getTableRow(divId,item,i);
	}
	htmlOutput += '</table>';
	htmlOutput += '</div>';

	htmlOutput += '<div style="font-size:8pt;color:#666666;font-style:italic;">Last updated at '+new Date().toLocaleTimeString()+'.  '+channeltitle+' updated every '+getUpdateInterval(updateInterval)+'</div>';

	return htmlOutput;
}

/**
 * This function returns an update interval
 * @param ms The update interval in milliseconds
 * @return The formatted update interval (e.g. 15 minutes, 1 hour)
 */
function getUpdateInterval(ms)
{
	seconds = ms / 1000;
	minutes = seconds / 60;
	hours = minutes / 60;

	if (hours <= 1)
	{
		if (minutes <= 1)
		{
			if (seconds <= 1)
			{
				return ms + ' milliseconds';
			}
			else return Math.round(seconds) + ' seconds.';
		}
		else return Math.round(minutes) + ' minutes.';
	}
	else return Math.round(hours) + ' hours.';
}

/**
 * This function get the HTML <tr> output for one RSS item
 * @param divId The id of the <div> in which to insert the RSS feed data
 * @param rssItem The RSSItem object for which to get the <tr> output
 * @param i The index of rssItem in its parent Array
 * @return trOutput The HTML <tr> markup for the RSS item
 */
function getTableRow(divId,rssItem,i)
{
	var id = divId + '_story_' + i;
	var trOutput = '';

	// Create the title attribute of this item's link with the truncated description text
	var title = removeMarkup(rssItem.getDescription()).substring(0,128) + '...';

	var report = rssItem.getLink();
	if (report.indexOf('story=') >= 0) {
		report = report.substring(report.indexOf('story=') + 6);
	} else {
		report = '';
	}	

	trOutput += '<tr>'
			+'<td style="vertical-align:top;padding:0px 5px;text-align:left;">&raquo;</td>'
			+'<td style="vertical-align:top;padding:0px 0px;text-align:left;">'
			+'<a style="color:#9f0000;font-weight:bold;" href= "javascript:try{report(\'NEWS_'+report+'\');}catch(e){}toggleDiv(\''+divId+'_story_'+i+'\');" title="'+title+'">'+rssItem.getTitle()+'</a>'
			+'<div style="display:none;" id="'+divId+'_story_'+i+'"><div style="font-style:italic;font-size:8pt;">'+rssItem.getPubDate()+'</div>'+rssItem.getDescription()
				+'<br /><p style="font-size:8pt;margin:0;padding:0;"><a target="_blank" href="'+rssItem.getLink()+'" style="text-decoration:none;font-weight:bold;color:#666666;">&raquo;View link</a></p></div>'
			+'</td>'
			+'</tr>';

	return trOutput;
}

/**
 * This function removes HTML tags and quotation marks from a string 
 * so that they can be safely displayed within a HTML tag attribute (e.g. the title attribute).
 * @param text The string from which to remove HTML tags and quotation marks
 * @return Returns a string without HTML tags and quotation marks
 */
function removeMarkup(text)
{
	return text.replace(/(<([^>]+)>)/ig,"").replace('"',''); 
}

/**
 * This function is used to toggle the display of the description
 * @param divId The id of the <div> that holds the description (initially hidden)
 */
function toggleDiv(divId)
{	//alert(divId);
	var mDiv = document.getElementById(divId);

	if (mDiv.style.display == 'none')
	{
		mDiv.style.display = 'block';
	}
	else if (mDiv.style.display == 'block')
	{
		mDiv.style.display = 'none';
	}
}

/**
 * This function parses an RSS pubDate and returns an RSSDate object
 * @param pubDate The RSS pubDate string
 * @return customDate The RSSDate object for the pubDate string
 */
function parseDate(pubDate)
{
	var dayKeys = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
	var dayVals = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];

	var monthKeys = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
	var monthVals = ['January','February','March','April','May','June','July','August','September','October','November','December'];

	var tokens = pubDate.split(" ");

	var mDay = "";
	var mDate = '';
	var mMonth = '';
	var mYear = '';
	var mTime = '';
	var mZone = '';

	var mHours = '';
	var mAdjHrs = '';
	var mMins = '';
	var mSecs = '';
	var mPeriod = '';


	if (tokens[0] != null) mDay = tokens[0];
	var idx = mDay.indexOf(",");
	if (idx != -1)
	{
		mDay = mDay.substring(0,idx);
		var loc = dayKeys.indexOf('Sat');
		//alert(dayKeys.indexOf(mDay));
		mDay = dayVals[dayKeys.indexOf(mDay)];
	}

	if (tokens[1] != null) mDate = tokens[1];

	if (tokens[2] != null) mMonth = tokens[2];
	mMonth = monthVals[monthKeys.indexOf(mMonth)];

	if (tokens[3] != null) mYear = tokens[3];

	if (tokens[4] != null) mTime = tokens[4];
	var timeTokens = mTime.split(":");
	if (timeTokens[0] != null)
	{
		mHours = timeTokens[0];
		if (mHours < 12)
		{
			mPeriod = 'A.M.';
			mAdjHrs = mHours - 0 + '';
		}
		else if (mHours > 12)
		{
			mPeriod = 'P.M.';
			mAdjHrs = mHours - 12 + '';;
		}
		else if (mHours == 0)
		{
			mPeriod = 'A.M.';
			mAdjHrs = 12 + '';
		}
		else if (mHours == 12)
		{
			mPeriod = 'P.M.';
			mAdjHrs = 12 + '';
		}
	}
	if (timeTokens[1] != null) mMins = timeTokens[1];
	if (timeTokens[2] != null) mSecs = timeTokens[2];
	mTime = mHours +':'+ mMins +' '+ mPeriod;
	
	if (tokens[5] != null) mZone = tokens[5];
	//alert(mDay+mMonth+mDate+mYear+mHours+mAdjHrs+mMins+mSecs+mPeriod+mZone);

	var customDate = new RSSDate(mDay,mMonth,mDate,mYear,mHours,mAdjHrs,mMins,mSecs,mPeriod,mZone);

	return customDate;
}

/**
 * This function converts an RSSDate object into a Javascript Date object
 * @param rssDate The RSSDate object to convert
 * @return Returns a new Javascript Date equivalent to the RSSDate object
 */
function getJsDate(rssDate)
{
	if (rssDate == null)
	{
		return new Date();
	}
	else
	{
		var dateString = '';

		dateString += rssDate.getMonth()
			+ ' ' + rssDate.getDate()
			+ ', ' + rssDate.getYear()
			+ ' ' + rssDate.getHours()
			+ ':' + rssDate.getMinutes()
			+ ':' + rssDate.getSeconds();

		return new Date(dateString);
	}
}

/**
 * This function formats and RSSDate object for display to the end-user
 * @param rssDate The RSSDate object to convert
 * @return Returns a formatted date string for the RSSDate
 */
function formatDate(rssDate)
{
	return rssDate.getDay() 
		+ ', ' + rssDate.getMonth() 
		+ ' ' + rssDate.getDate() 
		+ ', ' + rssDate.getYear() 
		+ ' at ' + rssDate.getAdjustedHours() + ':' + rssDate.getMinutes()
		+ ' ' + rssDate.getPeriod()
		+ ' ' + rssDate.getZone();
}

/**
 * This function and its prototypes below represent class of type RSSItem
 * @param title The title of the RSS item
 * @param description The description of the RSS item
 * @param pubDate The pubDate of the RSS item
 * @param link The link of the RSS item
 */
function RSSItem(title, description, pubDate, link, jsDate)
{
	this._title = title;
	this._descr = description;
	this._pubDt = pubDate;
	this._link = link;
	this._jsDate = jsDate;
}
RSSItem.prototype._title;
RSSItem.prototype._descr;
RSSItem.prototype._pubDt;
RSSItem.prototype._link;
RSSItem.prototype._jsDate;

RSSItem.prototype.getTitle = function() { return this._title;}
RSSItem.prototype.getDescription = function() { return this._descr;}
RSSItem.prototype.getPubDate = function() { return this._pubDt;}
RSSItem.prototype.getLink = function() { return this._link;}
RSSItem.prototype.getJsDate = function() { return this._jsDate;}
// end of class RSSItem

/**
 * This function and its prototypes below represent class of type RSSDate
 * @param day The day of the week
 * @param month The month of the year
 * @param date The date of the month
 * @param year The year
 * @param hours The hours of the day (24 hour format)
 * @param adjustedHours The hours of the day (adjusted for 12 hour format)
 * @param minutes The minutes of the hour
 * @param seconds The seconds of the minute
 * @param period The period (A.M. or P.M.)
 * @param zone The time zone (e.g. EST, EDT, etc.)
 */
function RSSDate(day,month,date,year,hours,adjustedHours,minutes,seconds,period,zone)
{
	this._day = day;
	this._month = month;
	this._date = date;
	this._year = year;
	this._hours = hours;
	this._adjustedHours = adjustedHours;
	this._minutes = minutes;
	this._seconds = seconds;
	this._zone = zone;
	this._period = period;
}
RSSDate.prototype._day;
RSSDate.prototype._month;
RSSDate.prototype._date;
RSSDate.prototype._year;
RSSDate.prototype._hours;
RSSDate.prototype._adjustedHours;
RSSDate.prototype._minutes;
RSSDate.prototype._seconds;
RSSDate.prototype._zone;
RSSDate.prototype._period;

RSSDate.prototype.getDay = function() { return this._day };
RSSDate.prototype.getMonth = function() { return this._month };
RSSDate.prototype.getDate = function() { return this._date };
RSSDate.prototype.getYear = function() { return this._year };
RSSDate.prototype.getHours = function() { return this._hours };
RSSDate.prototype.getAdjustedHours = function() { return this._adjustedHours };
RSSDate.prototype.getMinutes = function() { return this._minutes };
RSSDate.prototype.getSeconds = function() { return this._seconds };
RSSDate.prototype.getZone = function() { return this._zone };
RSSDate.prototype.getPeriod = function() { return this._period };
// end of class RSSItem

if(!Array.indexOf)
{
	Array.prototype.indexOf = function(obj){
		for(var i=0; i<this.length; i++)
		{
			if(this[i]==obj)
			{
				return i;
			}
		}
		return -1;
	}
}
