/**
 * Simple twitter-feeder
 * 
 * This javascript loops through last tweets from a specific feed.
 * By modifying the first values you can change a few parameters.
 * 
 * Installation can be done by the following steps:
 * - enter the twitter feed (twitfeed.feed_url)
 * - add a container with id 'twitfeed' to your HTML-page
 * - include this javascript in your HTML-page
 * 
 * Simple example:
 * <html><head>
 *   <script type="text/javascript" src="twitfeed.js"></script>
 *   <script type="text/javascript">
 *     window.onload = function() {
 *       var tf = new_horizontal_twitfeed();
 *       tf.init();
 *     }
 *   </script>
 * </head><body>
 *   <div id="twitfeed"><a href="http://twitter.com/garrcomm">Me @ twitter</a>:</div> 
 * </body></html>
 * 
 * If you would like to use twitfeed.php as proxy for your twitter feed,
 * you can use the source code available at www.stefan.co.
 * 
 * Changelog
 * ----------- 
 * 0.2 Made it possible to create multiple feeds
 * 
 * @author Stefan Thoolen <www.stefan.co>
 * @version 0.2
 * @package Twitfeed
 * @license WTFPL 
 */

/* This program is free software. It comes without any warranty, to
 * the extent permitted by applicable law. You can redistribute it
 * and/or modify it under the terms of the Do What The Fuck You Want
 * To Public License, Version 2, as published by Sam Hocevar. See
 * http://sam.zoy.org/wtfpl/COPYING for more details. */

/**
 * Sends back a twitfeed-object for a vertical non-scrolling twitter feed
 */
function new_vertical_twitfeed() {
	/**
	 * Starts a new twitfeed-object
	 */
	var twitfeed = new Object();
	// The URL of the twitter-feed
	twitfeed.feed_url = 'twitfeed.php';
	// Display your own name in front of your tweets
	twitfeed.display_self = false;
	// Hides the prefix if you are not the poster
	twitfeed.hide_prefix = true;
	// Container of the feed (when it's a string, it must be an element ID)
	twitfeed.parent = 'twitfeed';
	// Only displays the last x tweets
	twitfeed.max_tweets = 5;
	// Do we want to display timestamps?
	twitfeed.show_times = true;
	
	/**
	 * Initializes the twitfeed object
	 */
	twitfeed.init = function() {
		if (typeof twitfeed.parent == 'string') {
			var tf = document.getElementById(twitfeed.parent);
			twitfeed.parent = tf;
		} else {
			var tf = twitfeed.parent;
		}
		if (tf != null) {
			/**
			 * Dresses the twitfeed-DIV
			 */
			twitfeed.prefix_html = tf.innerHTML;
			tf.innerHTML = twitfeed.prefix_html + ' loading feed';
			
			/**
			 * Loads the twitterfeed
			 */
			twitfeed.posts = new Array();
			var loaderdots = window.setInterval(function() { tf.innerHTML += '.'; }, 100);
			twitfeed_helper.ajax_get_xml(twitfeed.feed_url, function (xmlobj) {
				window.clearInterval(loaderdots);
				/**
				 * Fetches the username
				 */
				var title = xmlobj.getElementsByTagName('title')[0].childNodes[0].nodeValue.split(' ');
				twitfeed.username = title[title.length - 1];
				/**
				 * Parses all posts
				 */
				var posts = xmlobj.getElementsByTagName('item');
				var feed_type = 'rss';
				if (posts.length == 0) {
					var posts = xmlobj.getElementsByTagName('entry');
					var feed_type = 'atom';
				}
				var global_html = '';
				for (var i = 0; i < posts.length; ++i) {
					twitfeed.posts[i] = new Object;
					if (feed_type == 'rss') {
						// RSS-feed
						var txt = posts[i].getElementsByTagName('description')[0].childNodes[0].nodeValue;
						var postername = txt.substr(0, txt.indexOf(':'));
						twitfeed.posts[i].text = txt.substr(txt.indexOf(':') + 1, txt.length);
						twitfeed.posts[i].url = posts[i].getElementsByTagName('link')[0].childNodes[0].nodeValue;
						twitfeed.posts[i].timestamp = Date.parse(posts[i].getElementsByTagName('pubDate')[0].childNodes[0].nodeValue);
					} else if(feed_type == 'atom') {
						// ATOM-feed
						var postername = posts[i].getElementsByTagName('author')[0].getElementsByTagName('name')[0].childNodes[0].nodeValue.split(' ')[0];
						twitfeed.posts[i].text = posts[i].getElementsByTagName('title')[0].childNodes[0].nodeValue;
						twitfeed.posts[i].url = posts[i].getElementsByTagName('link')[0].getAttribute('href');
						twitfeed.posts[i].timestamp = twitfeed_helper.xsd_dateTime(posts[i].getElementsByTagName('published')[0].childNodes[0].nodeValue);
					}
					// Formats the date
					if (twitfeed.show_times) {
						var dobj = new Date(); dobj.setTime(twitfeed.posts[i].timestamp);
						var fdate = '[' + dobj.toDateString();
						fdate += ' @ ' + dobj.toTimeString().substr(0, 8) + '] ';
					} else { var fdate = ''; }
					// Almost final HTML
					twitfeed.posts[i].html = fdate + twitfeed_helper.twitter_hyperlink(twitfeed.posts[i].text);
					// Shows the poster's name
					if (postername != twitfeed.username || twitfeed.display_self) {
						twitfeed.posts[i].html = '<a href="http://twitter.com/'+postername+'" target="_blank">'+postername+'</a>: '+twitfeed.posts[i].html;
					}
					// Shows the HTML prefix
					if (postername == twitfeed.username || !twitfeed.hide_prefix) {
						twitfeed.posts[i].html = twitfeed.prefix_html + twitfeed.posts[i].html;
					}
					// Last one?
					if (i == posts.length - 1 || i == twitfeed.max_tweets - 1) {
						global_html += '<div class="last">'+twitfeed.posts[i].html+'</div>';
						break;
					} else {
						global_html += '<div>'+twitfeed.posts[i].html+'</div>';
					}
				}
				tf.innerHTML = global_html;
			});
		}
	}
	
	return twitfeed;
}
/**
 * The following objects structure will be in vertical_twitfeed (only interesting for developers):
 * 
 * vertical_twitfeed
 *   +-- display_self            Boolean; Display your own name in front of your tweets
 *   +-- feed_url                String; The URL of the twitter-feed
 *   +-- init                    Function; Initializes the object
 *   +-- max_tweets              Integer; Only displays the last x tweets
 *   +-- parent                  Object; A HTML-element which will contain twitfeed.container
 *   +-- prefix_html             String; Prefix which will be added in front of all tweets
 *   `-- posts                   Array; an array with all tweets
 *   |     +-- html              String; the tweet text as HTML
 *   |     +-- text              String; the tweet text
 *   |     +-- timestamp         Integer; Timestamp (in miliseconds) of the tweet
 *   |     `-- url               String; URL referring to the tweet
 *   `-- show_times              Boolean; When true we also show timestamps 
 */
/**
 * Sends back a twitfeed-object for a horizontal scrolling twitter feed
 */
function new_horizontal_twitfeed() {
	/**
	 * Starts a new twitfeed-object
	 */
	var twitfeed = new Object();
	// The URL of the twitter-feed
	twitfeed.feed_url = 'twitfeed.php';
	// Every x miliseconds a new post will be displayed
	twitfeed.post_interval = 7500;
	// Scrolling starts after x miliseconds
	twitfeed.scroll_start_timeout = 1000;
	// Every x miliseconds the post will scroll to the left
	twitfeed.scroll_interval = 100;
	// Every 'scroll_interval' we will move x pixels
	twitfeed.scroll_step = 10;
	// Only displays the last x tweets
	twitfeed.max_tweets = 5;
	// Display your own name in front of your tweets
	twitfeed.display_self = false;
	// Hides the prefix if you are not the poster
	twitfeed.hide_prefix = true;
	// Container of the feed (when it's a string, it must be an element ID)
	twitfeed.parent = 'twitfeed';
	
	/**
	 * Initializes the twitfeed object
	 */
	twitfeed.init = function() {
		if (typeof twitfeed.parent == 'string') {
			var tf = document.getElementById(twitfeed.parent);
			twitfeed.parent = tf;
		} else {
			var tf = twitfeed.parent;
		}
		if (tf != null) {
			/**
			 * Dresses the twitfeed-DIV
			 */
			twitfeed.prefix_html = tf.innerHTML;
			tf.innerHTML = '';
			tf.style.overflow = 'hidden';
			if (tf.style.position != 'absolute' && tf.style.position != 'relative') {
				tf.style.position = 'relative';
			}
			
			/**
			 * Creates the container for the feed itself
			 */
			twitfeed.container = document.createElement('DIV');
			tf.appendChild(twitfeed.container);
			twitfeed.container.innerHTML = twitfeed.prefix_html + ' loading feed';
			twitfeed.container.style.whiteSpace = 'nowrap';
			twitfeed.container.style.overflow = 'visible';
			twitfeed.container.style.position = 'relative';
			
			/**
			 * Loads the twitterfeed
			 */
			twitfeed.posts = new Array();
			var loaderdots = window.setInterval(function() { twitfeed.container.innerHTML += '.'; }, 100);
			twitfeed_helper.ajax_get_xml(twitfeed.feed_url, function (xmlobj) {
				window.clearInterval(loaderdots);
				/**
				 * Fetches the username
				 */
				var title = xmlobj.getElementsByTagName('title')[0].childNodes[0].nodeValue.split(' ');
				twitfeed.username = title[title.length - 1];
				/**
				 * Parses all posts
				 */
				var posts = xmlobj.getElementsByTagName('item');
				for (var i = 0; i < posts.length; ++i) {
					twitfeed.posts[i] = new Object;
					var txt = posts[i].getElementsByTagName('description')[0].childNodes[0].nodeValue;
					var postername = txt.substr(0, txt.indexOf(':'));
					twitfeed.posts[i].text = txt.substr(txt.indexOf(':') + 1, txt.length);
					twitfeed.posts[i].url = posts[i].getElementsByTagName('link')[0].childNodes[0].nodeValue;
					twitfeed.posts[i].timestamp = Date.parse(posts[i].getElementsByTagName('pubDate')[0].childNodes[0].nodeValue);
					twitfeed.posts[i].html = twitfeed_helper.twitter_hyperlink(twitfeed.posts[i].text);
					// Shows the poster's name
					if (postername != twitfeed.username || twitfeed.display_self) {
						twitfeed.posts[i].html = '<a href="http://twitter.com/'+postername+'" target="_blank">'+postername+'</a>: '+twitfeed.posts[i].html;
					}
					// Shows the HTML prefix
					if (postername == twitfeed.username || !twitfeed.hide_prefix) {
						twitfeed.posts[i].html = twitfeed.prefix_html + twitfeed.posts[i].html;
					} 
				}
				
				/**
				 * Makes the twitfeed clickable
				 */
				twitfeed.container.onclick = function(e) {
					/**
					 * Event compatibility between IE and other browsers
					 */
					if (!e) var e = window.event;
					if (!e.target) e.target = e.srcElement;
					/**
					 * Only open this if the DIV is clicked, not if a hyperlink within the DIV is clicked
					 */
					if (e.target.tagName == 'DIV') {
						window.open(twitfeed.posts[twitfeed.posts_index].url, '_blank');
					}
				}
				twitfeed.container.style.cursor = 'pointer';
				
				/**
				 * Starts looping
				 */
				twitfeed.posts_index = -1;
				twitfeed.post_change();
				window.setInterval(twitfeed.post_change, twitfeed.post_interval);
			});
		}
	}
	
	/**
	 * Changes the post
	 */
	twitfeed.post_change = function() {
		/**
		 * Counter for the next text
		 */
		++twitfeed.posts_index;
		if (twitfeed.posts_index >= twitfeed.posts.length || twitfeed.posts_index >= twitfeed.max_tweets) twitfeed.posts_index = 0;
		/**
		 * Displays the new text
		 */
		twitfeed.container.innerHTML = twitfeed.posts[twitfeed.posts_index].html;
		/**
		 * Do we need scrolling?
		 */
		window.clearInterval(twitfeed.scroll_interval_id);
		window.clearTimeout(twitfeed.scroll_timeout_id);
		twitfeed.container.style.left = '0px';
		twitfeed.container.width_total = twitfeed.container.parentNode.scrollWidth;
		twitfeed.container.width_visible = twitfeed.container.parentNode.offsetWidth;
		if (twitfeed.container.width_total > twitfeed.container.width_visible) {
			twitfeed.scroll_direction = 0 - twitfeed.scroll_step;
			twitfeed.scroll_timeout_id = window.setTimeout(function() {
				twitfeed.scroll_interval_id = window.setInterval(twitfeed.scroll_action, twitfeed.scroll_interval);
			}, twitfeed.scroll_start_timeout);
		}
	}
	
	/**
	 * Executes the scrolling
	 */
	twitfeed.scroll_action = function() {
		var curr_left = parseInt(twitfeed.container.style.left, 10);
		var reset_interval = false;
		if (twitfeed.scroll_direction < 0 && curr_left + twitfeed.container.width_total > twitfeed.container.width_visible) {
			curr_left += twitfeed.scroll_direction;
			twitfeed.container.style.left = curr_left+'px';
		} else if(twitfeed.scroll_direction < 0) {
			reset_interval = true;
		} else if (twitfeed.scroll_direction > 0 && curr_left < 0) {
			curr_left += twitfeed.scroll_direction;
			twitfeed.container.style.left = curr_left+'px';
		} else if(twitfeed.scroll_direction > 0) {
			reset_interval = true;
		}
		if (reset_interval) {
			twitfeed.scroll_direction = 0 - twitfeed.scroll_direction;
			window.clearInterval(twitfeed.scroll_interval_id);
			window.clearTimeout(twitfeed.scroll_timeout_id);
			twitfeed.scroll_timeout_id = window.setTimeout(function() {
				twitfeed.scroll_interval_id = window.setInterval(twitfeed.scroll_action, twitfeed.scroll_interval);
			}, twitfeed.scroll_start_timeout);
		}
	}
	
	return twitfeed;
}

/**
 * The following objects structure will be in horizontal_twitfeed (only interesting for developers):
 * 
 * horizontal_twitfeed
 *   +-- container               Object; A DIV-element which will contain the tweet texts
 *   |     +-- width_total       Integer; The total width of the current tweet in pixels
 *   |     `-- width_visible     Integer; The visible width of the current tweet in pixels
 *   +-- display_self            Boolean; Display your own name in front of your tweets
 *   +-- feed_url                String; The URL of the twitter-feed
 *   +-- init                    Function; Initializes the object
 *   +-- max_tweets              Integer; Only displays the last x tweets
 *   +-- parent                  Object; A HTML-element which will contain twitfeed.container
 *   +-- prefix_html             String; Prefix which will be added in front of all tweets
 *   +-- post_change             Function; Displays the next tweet
 *   +-- post_interval           Integer; Every x miliseconds a new post will be displayed
 *   +-- posts                   Array; an array with all tweets
 *   |     +-- html              String; the tweet text as HTML
 *   |     +-- text              String; the tweet text
 *   |     +-- timestamp         Integer; Timestamp (in miliseconds) of the tweet
 *   |     `-- url               String; URL referring to the tweet
 *   +-- posts_index             Integer; Index of the currently displayed tweet
 *   +-- scroll_action           Function; Does the actual scrolling
 *   +-- scroll_direction        Integer; The direction in which we are scrolling (above or below zero)
 *   +-- scroll_interval         Integer; Every x miliseconds the post will scroll to the left
 *   +-- scroll_interval_id      Integer; Handle to the setInterval for scrolling
 *   +-- scroll_start_timeout    Integer; Scrolling starts after x miliseconds
 *   +-- scroll_step             Integer; Every 'scroll_interval' we will move x pixels
 *   `-- scroll_timeout_id       Integer; Handle to the setTimeout for scrolling
 */

/**
 * Will contain some generic functions
 */
var twitfeed_helper = new Object();

/**
 * Generic AJAX-caller
 */
twitfeed_helper.get_xml_http_request = function() {
	if (window.XMLHttpRequest) {
		// code for IE7+, Firefox, Chrome, Opera, Safari
		return new XMLHttpRequest();
	}
	if (window.ActiveXObject) {
		// code for IE6, IE5
		return new ActiveXObject("Microsoft.XMLHTTP");
	}
	return null;
}

/**
 * Ajax request helper
 */
twitfeed_helper.ajax_get_xml = function(url, output) {
	var obj = twitfeed_helper.get_xml_http_request();
	obj.open('GET', url, true);
	obj.onreadystatechange = function() {
		if (obj.readyState == 4) {
			output(obj.responseXML.documentElement);
		}
	}
	obj.send();
}

/**
 * Converts an ATOM time to a JavaScript timestamp
 */
twitfeed_helper.xsd_dateTime = function(datetime) {
	var newstr = datetime.substr(0, 10).replace(/\-/g, '/')+' '+datetime.substr(11, 8);
	if (datetime.substr(19, 1) == 'Z') newstr += ' +0000'; else newstr += ' '+datetime.substr(19);
	return Date.parse(newstr);
}
	
/**
 * Automaticly makes hyperlinks in a tweet
 */
twitfeed_helper.twitter_hyperlink = function(txt) {
	txt = txt.replace(/(http\:\/\/[0-9\_\-\.A-Z\/\%]{1,1024})/ig, '<a href="$1" target="_blank">$1</a>');
	txt = txt.replace(/\@([0-9\_A-Z]{1,64})/ig, '@<a href="http://twitter.com/$1" target="_blank">$1</a>');
	txt = txt.replace(/\#([0-9\_A-Z]{1,64})/ig, '<a href="http://twitter.com/search?q=%23$1" target="_blank">#$1</a>');
	return txt;
}

