/**
 * @author Petar Španja
 * @emails petar@netgen.hr
 * @web www.netgen.hr
 */
(function($) {
	var TweetBox = function () {
		var defaults = {
				username: ['twitter'],											// [string|array]		username or array of usernames
				list: null,																	// [string]					optional name of list belonging to username
				image_size: 48,															// [integer]				height and width of user image if displayed (48px max)
				count: 10,																	// [integer]				number of tweets to display
				text_loading: 'Učitavam tweetove...',				// [string]					optional loading text, displayed while loading tweets
				text_no_tweets: 'Nema tweetova!',						// [string]					optional text, displayed on first load when no tweets are found
				query: null,																// [string]					optional search query
				refresh: 0,																	// [integer]				refresh interval in miliseconds, zero to disable
				onInsert: function(){return true;},					// [function]				triggered when single tweet is inserted
				onRemove: function(){return true;},					// [function]				triggered when tweet is removed from the list
				onRefresh: function(){return true;},				// [function]				triggered when new tweets are fetched
				onLoad: function(){return true;}						// [function]				triggered when tweets are loaded for the first time
			},
			template = {
				wrapper: [
				'<ul class="tweet-list"><%=list_items%></ul>'
				],
				list_item: [
				'<li class="tweet-line float-break<%=refreshed%>">',
					'<div class="wrapper">',
						//'<a href="http://twitter.com/<%=user_name%>" class="tweet-user-image">',
						//	'<img width="<%=user_image_size%>" height="<%=user_image_size%>" border="0" title="<%=user_name%>" alt="<%=user_name%>" src="<%=user_image_src%>" />',
						//'</a>',
						'<p class="tweet-message">',
							//'<a class="tweet-author" href="http://twitter.com/<%=user_name%>"><%=user_name%></a>',
							'<%=tweet_text%>',
							'<em class="tweet-time-reply">',
								'<a class="tweet-time" title="view tweet on twitter" href="<%=tweet_link%>" rel="<%=tweet_created_at%>"><%=tweet_time%></a> | ',
								'<a class="tweet-reply" href="http://twitter.com/?status=@<%=user_name%>%20&in_reply_to_status_id=<%=tweet_id%>&in_reply_to=<%=user_name%>">reply</a>',
							'</em>',
						'</p>',
					'</div>',
				'</li>'
				]
			},
			link_stuff = function (text, options) {
				// link urls, users, hashes
				var from = options.username.join("%2BOR%2B");
				return text.
					replace(/((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi, '<a class="url" href="$1" target="_blank">$1</a>').
					replace(/[\@]+([A-Za-z0-9-_]+)/gi, '<a class="user" href="http://twitter.com/$1" target="_blank">@$1</a>').
					replace(/(?:^| )[\#]+([A-Za-z0-9-_]+)/gi, ' <a class="tag" href="http://search.twitter.com/search?q=&tag=$1&lang=all' + (from ? '&from=' + from : '') + '" target="_blank">#$1</a>');
			},
			parse_date = function (date_str) {
				// The non-search twitter APIs return inconsistently-formatted dates, which Date.parse
				// cannot handle in IE. We therefore perform the following transformation:
				// "Wed Apr 29 08:53:31 +0000 2009" => "Wed, Apr 29 2009 08:53:31 +0000"
				return Date.parse(date_str.replace(/^([a-z]{3})( [a-z]{3} \d\d?)(.*)( \d{4})$/i, '$1,$2$4$3'));
			},
			relative_time = function (time_value) {
				var parsed_date = parse_date(time_value);
				var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
				var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);
				var pluralize = function (singular, n) {return '' + n + ' ' + singular + (n == 1 ? '' : 's');};
				if (delta < 5)											return 'just now';
				else if (delta < 20)								return 'seconds ago';
				else if (delta < 60)								return 'a minute ago';
				else if (delta < (60*60))						return pluralize("minute", parseInt(delta / 60)) + ' ago';
				else if (delta < (24*60*60))				return 'about ' + pluralize("hour", parseInt(delta / 3600)) + ' ago';
				else if (delta < (24*60*60*30))			return 'about ' + pluralize("day", parseInt(delta / 86400)) + ' ago';
				else if (delta < (24*60*60*30*12))	return 'about ' + pluralize("month", parseInt(delta / 2592000)) + ' ago';
				else																return 'about ' + pluralize("year", parseInt(delta / 31536000)) + ' ago';
			},
			build_url = function (since_id, options) {
				var proto = ('https:' == document.location.protocol ? 'https:' : 'http:');
				if (options.list) {
					return proto+"//api.twitter.com/1/" + options.username[0] + "/lists/" + options.list + "/statuses.json?per_page=" +
						(since_id ? options.count : options.count) + (since_id ? '&since_id=' + since_id : '') + "&callback=?";
				} else if (options.query == null && options.username.length == 1) {
					return proto+'//api.twitter.com/1/statuses/user_timeline.json?screen_name=' + options.username[0] + '&count=' + options.count + (since_id ? '&since_id=' + since_id : '') + '&callback=?';
				} else {
					var query = (options.query || 'from:' + options.username.join(' OR from:'));
					return proto + '//search.twitter.com/search.json?&q=' + escape(query) + '&rpp=' + options.count + (since_id ? '&since_id=' + since_id : '') + '&callback=?';
				}
			},
			process_tweets = function (widget) {
				var options = widget.data('tweetbox');
				widget.find('.tweet-refreshed:last').each(function(){
					var height = $(this).height();
					$(this).height(0).removeClass('tweet-refreshed').find('div').hide();
					classify_tweets(widget);
					$(this).animate({height:height}, 500, 'linear', function(){
						$(this).height('auto').find('div').fadeIn(500, function(){
							options.onInsert.apply(widget);
							widget.has('.tweet-refreshed').length ? process_tweets(widget) : null;
						});
					});
					widget.find('.tweet-line:gt(' + (options.count - 1) + '):last').slideUp(500, function(){
						$(this).remove();
						options.onRemove.apply(widget);
					});
				});
			},
			classify_tweets = function (widget) {
				var options = widget.data('tweetbox');
				widget.find('.tweet-line').removeClass('first last even odd');
				widget
					.find('.tweet-line:not(.tweet-refreshed):first').addClass('first').end()
					.find('.tweet-line:not(.tweet-refreshed):last, .tweet-line:not(.tweet-refreshed):eq(' + (options.count - 1) + ')').addClass('last').end()
					.find('.tweet-line:not(.tweet-refreshed):odd').addClass('even').end()
					.find('.tweet-line:not(.tweet-refreshed):even').addClass('odd');
			},
			fetch_tweets = function (widget, refresh) {
				var options = widget.data('tweetbox');
				clearTimeout(widget.data('timer'));
				refresh = typeof(refresh) != 'undefined' ? refresh : false;
				var list_items = '';
				var since_id = false;
				if (refresh) {
					widget.addClass('tweetbox-refreshing');
					if (widget.has('.tweet-line').length) {
						widget.find('a.tweet-time').each(function(i){$(this).html(relative_time($(this).attr('rel')));});
						since_id = widget.find('.tweet-line:first a.tweet-time').attr('href').match(/\b(\d+)\b/)[1];
					}
				}
				else {
					widget.addClass('tweetbox-loading');
				}
				$.getJSON(build_url(since_id, options), function(data){
					var tweets = (data.results || data);
					widget.removeClass('tweetbox-loading tweetbox-refreshing');
					$.each(tweets, function(i, item){
						var from_user = item.from_user || item.user.screen_name;
						var template_vars = {
							user_name:				from_user,
							user_image_size:	options.image_size,
							user_image_src:		item.profile_image_url || item.user.profile_image_url,
							tweet_link:				'http://twitter.com/' + from_user + '/statuses/' + item.id_str,
							tweet_id:					item.id,
							tweet_text:				link_stuff(item.text, options),
							tweet_created_at:	item.created_at,
							tweet_time:				relative_time(item.created_at),
							refreshed:				(refresh ? ' tweet-refreshed' : '')
						}
						list_items += tpl(template.list_item.join(''), template_vars);
					});
					if (!refresh) {
						widget.find('.tweets').append(tpl(template.wrapper.join(''), {list_items:list_items}));
						classify_tweets(widget);
						if (!list_items) widget.find('.status-no-tweets').show();
						options.onLoad.apply(widget);
					}
					else if (list_items) {
						widget.find('.status-no-tweets').hide();
						widget.find('.tweet-list').prepend(list_items);
						process_tweets(widget);
					}
					if (list_items) options.onRefresh.apply(widget);
					if (options.refresh) widget.data('timer', setTimeout(function(){fetch_tweets(widget, true)}, options.refresh));
				});
			}
		return {
			init: function(options) {
				options = $.extend({}, defaults, options||{});
				return this.each(function(i, widget){
					widget = $(widget);
					widget.attr('id', 'tweetbox_' + parseInt(Math.random() * 1000)).data('tweetbox', options);
					if (typeof(options.username) == "string") options.username = [options.username];
					widget.find('.status-loading .text').html(options.text_loading);
					widget.find('.tweetbox-opentwitter').attr('href', 'http://twitter.com/' + (options.query ? '#search?q=' + escape(options.query) : options.username[0]));
					widget.find('.status-no-tweets .text').html(options.text_no_tweets);
					widget.find('.tweetbox-refresh').click(function(){fetch_tweets(widget, true); return false;});
					fetch_tweets(widget);
				});
			},
			refresh: function() {return this.each(function(i, widget) {if ($(widget).data('tweetbox')) fetch_tweets($(widget), true);});}
		}
	}();//TweetBox
	$.fn.extend({
		TweetBox: TweetBox.init,
		TweetBoxRefresh: TweetBox.refresh
	});
})(jQuery);
(function(){
	var cache = {};
	this.tpl = function tpl(str, data){
		// Figure out if we're getting a template, or if we need to load the template - and be sure to cache the result.
		var fn = !/\W/.test(str) ? cache[str] = cache[str] || tpl(document.getElementById(str).innerHTML) :
			// Generate a reusable function that will serve as a template generator (and which will be cached).
			new Function("obj", "var p=[],print=function(){p.push.apply(p,arguments);};" +
				// Introduce the data as local variables using with(){}
				"with(obj){p.push('" +
				// Convert the template into pure JavaScript
				str.replace(/[\r\t\n]/g, " ").split("<%").join("\t").replace(/((^|%>)[^\t]*)'/g, "$1\r").replace(/\t=(.*?)%>/g, "',$1,'").split("\t")
					.join("');").split("%>").join("p.push('").split("\r").join("\\'") + "');}return p.join('');");
		// Provide some basic currying to the user
		return data ? fn(data) : fn;
	};
})();
