/* 	Twitter Friends v1.0
	Blog : http://www.moretechtips.net
	Project: http://code.google.com/p/twitter-friends-widget/
	Copyright 2009 [Mike @ moretechtips.net] 
	Licensed under the Apache License, Version 2.0 
	(the "License"); you may not use this file except in compliance with the License. 
	You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
*/


(function($){ 
		
$.fn.twitterFriends = function(allOptions) {  
	// This default options will apply on all matched elements unless element has his own options
	var defaults = {
		debug:1
		,username:''
		,friends:0
		,users:40
		,loop:1
		,user_link:0
		,user_image:20
		,user_animate:'opacity'
		,user_change:200
		,user_swap:5000
		,user_append:1
		,header:''
		,tweet:0
		,tweet_avatar:1
		,tweet_author:0
		,tweet_date:1
		,tweet_source:1
		,tweet_image:48
		,tweet_stay:5000
		,tweet_change:200
		,tweet_animate:'opacity'
		,info:''
	};
	allOptions = $.extend({}, defaults, allOptions);
		
	return this.each(function() {  
		// output init or not
		var wasOutput = 0;
		// users
		var rs = [];
		// visible page, avatar index, tweet index
		var vp = -1,ai=-1,si=-1;
		// this div, users div , tweet div, header div
		var div = $(this), usrsDiv=null, stsDiv=null, hdDiv=null;

		//override passed options by element embedded options if any
		var op = allOptions;
		if (div.attr('options')) {
			try { 
				op = eval('('+div.attr('options')+')'); 
			} catch(e) { 
				div.html('<b style="color:red">'+e+'</b>');
				return;
			};
			op = $.extend({}, defaults, op);
		};
		//request friends/followers
		var requestUsers = function() {
			var url = op.friends? 'http://twitter.com/statuses/friends.json' : 'http://twitter.com/statuses/followers.json';
			var data = {screen_name:op.username,cursor:-1};
			$.ajax({url:url,data:data,success:requestedUsers,dataType:'jsonp',cache:true});
		};
		//friends/followers was requested
		var requestedUsers = function(json){
			// Error!
			if(!json.users){
				if(op.debug) div.html('<b style="color:red">Error:'+(json.error? json.error:'unkown')+'</b>');
				return; //exit
			};
			//keep new one last
			rs = json.users.reverse();
			//no results 
			if(rs.length==0) return;
			//Start output 
			output();

			// reset page index 
			vp=-1;
			addUsers();
		};
		// add users icons but hidden
		var addUsers= function() {
			// users list end, loop ?
			if( (vp+1)*op.users >=rs.length) {
				//reset page index ?
				if(op.loop) vp = -1;
				else return;
			};
			usrsDiv.html('');
			//next visible page
			vp++;
			//Add 
			for(var i=vp*op.users; i<(vp+1)*op.users; i++) {
				if(i>=rs.length) break;
				addUser(rs[i],i);
			};
			
			// reset show avatar index and start show sequence
			ai= op.user_append? -1 : $('a',usrsDiv).length;
			//start showing them
			showUser();
			
			// reset visible tweet index and start hide/show sequence
			si= -1;
			if(op.tweet) hideStatus();
		};
		// add hidden user icon
		var addUser = function(x,i) {
			var u = op.user_link && x.url? x.url :'http://www.ayojak.com/fan';
			var t = x.name + (x.status && op.tweet ?': '+ x.status.text :'');
			t= t.replace(/"/g,'&quot;').replace(/'/g,'&#39;');
			$('<a style="display:none;height:'+op.user_image+'px" href="'+u+'" title="'+ t +'">'
				+'<img src="'+x.profile_image_url+'" border="0" height="'+op.user_image+'" width="'+op.user_image+'"/>'
			+'</a>').appendTo(usrsDiv);
		};
		// recursive fn to show user one by one
		var showUser= function(){
			ai= op.user_append? ai+1 : ai-1;
			//create effect param and set it show
			var x = $('a:eq('+ai+')',usrsDiv);
			if(!x.length) {
				// no more users in current visible page
				// move next page after dummy effect if tweet is off
				if(!op.tweet) usrsDiv.animate({opacity:1},op.user_swap,"linear", addUsers);
				return;
			};
			var effect = new Object; effect[op.user_animate] = 'show';
			x.animate(effect,op.user_change,"linear", showUser);
		};
		
		// add tweet of current user
		var addStatus = function(x,s) {
			//Init style as hidden
			var u = op.user_link && x.url? x.url :'http://www.ayojak.com/fan';
			var t = x.name;
			stsDiv.html('<div style="display:none;">'
				+ (op.tweet_avatar? '<span class="tf-avatar">'
					+'<a href="http://www.ayojak.com/fan" title="'+t+'">'
						+'<img src="'+ x.profile_image_url +'" height="'+op.tweet_image+'" width="'+op.tweet_image+'" border="0"/>'
					+'</a>'
				+'</span>' :'')
				+'<span class="tf-body">'
					+(op.tweet_author? '<strong>'
						+'<a href="'+u+'" title="'+t+'">'+ x.screen_name +'</a>'
					+'</strong>' :'')
					+'<span class="tf-content">'+ linkify(s.text) +'</span>'
					+'<span class="tf-meta">'
						+ (op.tweet_date? '<a class="tf-date" href="http://twitter.com/'+ x.screen_name +'/status/'+ s.id +'">'
							+ formatDate(s.created_at)
						+'</a>' :'')
						+ (op.tweet_source? '<span class="tf-source"> from '+ decodeHTML(s.source) +'</span>' :'')
					+'</span>'
				+'</span>'
			+'</div>');
		};
		
		// hide the current tweet
		var hideStatus = function(){
			if (si>-1) $('div',stsDiv).fadeOut(op.tweet_change,showStatus);
			else showStatus();
		};
		// show the next tweet
		var showStatus = function(){
			//Increment tweet index , loop cause some users will come without tweet
			var x=null,s=null;
			while(!s) {
				si++;
				//next users set
				if (si >= $('a',usrsDiv).length) {
					addUsers();
					return;
				};
				x = rs[vp*op.users + si];
				s = x.status;
			};
			//add current tweet
			addStatus(x,s);
			
			//create effect param and set it show
			var effect = new Object; effect[op.tweet_animate] = 'show';
			$('div',stsDiv).animate(effect,op.tweet_change,"linear", stayStatus);
		};
		// Dummy fade in effect to keep current link for a while
		var stayStatus = function(){
			$('div',stsDiv).animate({opacity:1},op.tweet_stay,"linear", hideStatus);
		};
		
		//parse links, user id's, hashtags
		var linkify= function(d){
			return d.replace(/\bhttps?\:\/\/\S+/gi, function(b){
				var c='';
				b= b.replace(/(\.*|\?*|\!*)$/,function(m,a){
					c=a;
					return ''
				});
				return '<a class="tf-link" href="'+b+'">'+((b.length>25)?b.substr(0,24)+'...':b)+'</a>'+c;
			})
			.replace(/\B\@([A-Z0-9_]{1,15})/gi,'@<a class="tf-at" href="http://twitter.com/$1">$1</a>')
			.replace(/\B\#([A-Z0-9_]+)/gi,'<a class="tf-hashtag" href="http://search.twitter.com/search?q=%23$1">#$1</a>')
		};
		//decode html at source
		var decodeHTML = function(s) {
			return s.replace(/&lt;/gi,'<').replace(/&gt;/gi,'>').replace(/&quot;/gi,'"');
		};
		// Format publish date 
		var formatDate = function(s){
			//"Thu Oct 22 00:29:53 +0000 2009" for IE should be "Thu, 22 Oct 2009 02:27:47 +0000"
			if (/^(\w\w\w) (\w\w\w) (\d\d?) (\d\d?:\d\d?:\d\d?) ([\+\-]\d+) (\d\d\d\d)$/i.test(s))
			s = s.replace(/^(\w\w\w) (\w\w\w) (\d\d?) (\d\d?:\d\d?:\d\d?) ([\+\-]\d+) (\d\d\d\d)$/i, '$1, $3 $2 $6 $4 $5');
			
			var dat = new Date(),tody = new Date();
			dat.setTime(Date.parse(s));
			var td = tody.getDate(), tm = tody.getMonth()+1, ty = tody.getFullYear(), th = tody.getHours(), tmn = tody.getMinutes(), ts = tody.getSeconds();
			var d = dat.getDate(), m = dat.getMonth()+1, y = dat.getFullYear(), h = dat.getHours(), mn = dat.getMinutes(), s = dat.getSeconds();
			//today
			if (y==ty && m==tm && d==td) {
				var dh = th-h;
				if (dh>0) return dh+' hour'+(dh>1?'s':'')+' ago';
				var dmn = tmn-mn;
				if (dmn>0) return dmn+' minute'+(dmn>1?'s':'')+' ago';
				var ds = ts-s;
				return ds+' second'+(ds>1?'s':'')+' ago';
			}
			//Old one
			else return m+'/'+d+'/'+y;
		};
		
		//Get my info
		var requestMe = function() {
			$.ajax({url:'http://twitter.com/users/show.json'
					,data:{screen_name:op.username}
					,success:requestedMe
					,dataType:'jsonp'
					,cache:true});
		};
		//my info is loaded
		var requestedMe = function(j){
			output();
			// Errors!
			if(!j.screen_name){
				if(op.debug) hdDiv.html('<b style="color:red">Error:'+(j.error? j.error:'unkown')+'</b>');
				return; //exit
			};
			// write header
			hdDiv.html(op.header.replace(/_tp_/g, 'http://twitter.com/'+j.screen_name)
								.replace(/_fr_/g, j.friends_count)
								.replace(/_fo_/g, j.followers_count)
								.replace(/_ti_/g, j.profile_image_url)
			)
		};
		// Init
		var init = function() {
			if(op.header) requestMe();
			requestUsers();
		};
		// start output
		var output = function(){
			if(wasOutput) return; else wasOutput=1;
			div.html('');
			if(op.info) div.append(op.info); 
			//Add header div if enabled
			if(op.header) hdDiv = $('<div class="tf-header"></div>').appendTo(div); 
			//Add users div
			usrsDiv = $('<div class="tf-users"></div>').appendTo(div); 
			//Add tweet div if tweet on
			if(op.tweet) stsDiv = $('<div class="tf-tweet"></div>').appendTo(div); 
		};
		//start 
		init();
	});  
}

})(jQuery);  
//auto load div with class set to related-tweets
jQuery(document).ready(function(){
	jQuery('div.twitter-friends').twitterFriends();
});
