﻿(function($, doc, win, undefined){

	$.extend($.fn, {
		Twitter: function(user, options){
			options = $.extend(true, {}, $.Twitter.defaults, options);
			
			if(!user){
				throw "Geen gebruiker opgegeven!";
			}
			
			var root = this,
				list = $("<ul/>").appendTo(root),
				http = "http://twitter.com/",
				json = "http://api.twitter.com/1/statuses/user_timeline.json?screen_name=" + user + "&callback=?&count=" + options.numberOfTweets + "&include_rts=1&trim_user=1",
				regex = {
					url: "((https?|s?ftp|ssh)\\:\\/\\/[^\"\\s\\<\\>]*[^.,;'\">\\:\\s\\<\\>\\)\\]\\!])",
					RT: "^RT:?\\s@([a-z0-9]*):",
					user: "@([a-z0-9]*)",
					hash: "#([a-z0-9]*)"
				}, timer, xhr;
			regex.global = [regex.url, regex.RT, regex.user, regex.hash].join("|");
			
			// add referer link;
			if(options.addReferer){
				root.append($("<a/>").attr("href", http + user).text(options.text.referer));
			}
			
			// http://twitter.com/javascripts/blogger.js
			function relative_time(time_value) {
				var values = time_value.split(" ");
				time_value = values[1] + " " + values[2] + ", " + values[5] + " " + values[3];
				var parsed_date = Date.parse(time_value);
				var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
				var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);
				delta = delta + (relative_to.getTimezoneOffset() * 60);

				if (delta < 60) {
					return 'minder dan een minuut geleden';
				} else if(delta < 120) {
					return 'een minuut geleden';
				} else if(delta < (60*60)) {
					return (parseInt(delta / 60)).toString() + ' minuten geleden';
				} else if(delta < (120*60)) {
					return 'een uur geleden';
				} else if(delta < (24*60*60)) {
					return '' + (parseInt(delta / 3600)).toString() + ' uren geleden';
				} else if(delta < (48*60*60)) {
					return '1 dag geleden';
				} else {
					return (parseInt(delta / 86400)).toString() + ' dagen geleden';
				}
			}
			
			$.extend(root, {
				Update: function(){
					var timeout;
					
					xhr = $.getJSON(json, function(tweets) {
						var tweetIDs = [];  // used in remove controle below;

						win.clearTimeout(timeout);  // success, so clear the timeout;
						root.removeClass("error busy");

						// add new tweets;
						$.each(tweets, function(i, data) {
							tweetIDs.push(data.id.toString());  // used in remove controle below;

							if (!$("#tweet" + data.id, list).length) {
								var tweet = $("<li/>").hide().attr("id", "tweet" + data.id).append(
									$("<span/>").html(
										(data.truncated && data.retweeted_status && new RegExp(regex.RT, "i").test(data.text) 
											? data.text.match(new RegExp(regex.RT, "i"))[0] + " " + data.retweeted_status.text : data.text).toString()
										.replace("<", "&lt;").replace(">", "&gt;")
										.replace(new RegExp(regex.global, "gi"), function(str, p_url, p_url2, p_rt, p_user, p_hash, offset, s){
											if(p_url){
												return "<a href=\"" + p_url + "\" class=\"url\" rel=\"nofollow\">" + p_url + "</a>";
											} else if(p_rt){
												return "<a href=\"" + http + p_rt + "\" class=\"retweet\" rel=\"nofollow\">" + p_rt + "</a>";
											} else if(p_user){
												return "@<a href=\"" + http + p_user + "\" class=\"user\" rel=\"nofollow\">" + p_user + "</a>";
											} else if(p_hash){
												return "<a href=\"" + http + "search?q=%23" + p_hash + "\" class=\"hashtag\" rel=\"nofollow\">#" + p_hash + "</a>";
											}
											return str;
										})
									)
								).append(  // meta (date & source & geo);
									$("<span/>").addClass("meta").append(function(){
										return (options.addGeo && data.geo ? options.text.metaWithGeo : options.text.meta)
											.replace("$date$", function(){
												return "<a href=\"" + http + user + "/statuses/" + data.id +"\" title=\"" + data.created_at + "\">" + relative_time(data.created_at) + "</a>";
											}).replace("$source$", data.retweeted_status ? data.retweeted_status.source : data.source)
											.replace("$geo$", function(){
												return "<a href=\"http://maps.google.com/maps?q=" + data.geo.coordinates.join(",") + "\" class=\"geo\" title=\"" + data.place.country + "\">" + data.place.full_name + "</a>";
											});
									})
								).append(  // retweeted by you;
									data.retweeted_status ? 
										$("<span/>").addClass("meta").append(function(){
											return options.text.retweeted.replace("$user$", "<a href=\"" + http + user + "\" class=\"user\" rel=\"nofollow\">" + user + "</a>");
										}) : false
								);

								var li = list.find("li:first");
								while(li.length && data.id < parseInt(li.attr("id").replace("tweet", ""))){
									li = li.next();
									if(!li.length){
										break;
									}
								}
								if(li.length){  // before another tweet;
									li.before(tweet);
								} else {  // empty list or a too old tweet;
									list.append(tweet);
								}
								tweet.slideDown(1000);
							}
						});

						// remove old or deleted tweets;
						$("li", list).each(function() {
							var tweet = $(this);
							if ($.inArray(tweet.attr("id").replace("tweet", ""), tweetIDs) == -1) {
								tweet.hide("slow", function() {
									$(this).remove();
								}).slideUp(1000);
							}
						});
					});
					
					root.addClass("busy").removeClass("error");
					
					// stupid timeout controle, as json & jsonp don't call the error event;
					timeout = win.setTimeout(function(){
						root.addClass("error").removeClass("busy");
						xhr && xhr.abort();
					}, options.timeout);
					
					return this;
				},
				Stop: function(){
					win.clearInterval(timer);
					root.removeClass("error busy");
					return this;
				}
			});
			
			// update interval;
			if(options.updateInterval > 0){
				timer = win.setInterval(function(){
					root.Update();
				}, options.updateInterval);
			}
			
			// initial update;
			return root.Update();
		}
	});

	$.Twitter = {
		defaults: {
			updateInterval: 60 * 1000,  // public timeline is cached for 60 seconds;
			timeout: 5 * 1000,
			numberOfTweets: 4,
			addReferer: false,
			addGeo: true,
			text: {
				referer: "Volg ons op twitter",
				meta: "$date$ via $source$",
				metaWithGeo: "$date$ via $source$ van $geo$",
				retweeted: "Retweeted door $user$"
			}
		}
	};

})(jQuery, document, window);

	(function($){  // private closure;  
			$(function(){  // document loaded;
			
				$("#twitter").empty().Twitter("excelsior31", { 
					updateInterval: 3 * 60 * 1000,
					numberOfTweets: 4 
				});
				
			});
		})(jQuery);
