/*
	jQuery Scrolling Tweet Ticker 1.0.1 (May 18, 2010)
	Copyright 2010 Scott Langendyk. All Rights Reserved.
	
	==============================================================================
	Basic Usage
	==============================================================================
		$('#tweetticker').tweetTicker({
			username : 'username'
		});
	
	*For additional documentation please reference readme.txt
*/

(function($){

    $.fn.tweetTicker = function(options){
    	var options = $.extend({}, $.fn.tweetTicker.defaults, options);
    	
    	var tweetTicker;
		var tweetsList;
		var overflowContainer;
		var loading;
	
		var appendThreshhold;
		var currentTweet;
		var listWidth;
		var currentRate;
		var preAppendThreshhold;
	
		var updateFlag = false;
		var failedFetchAttempts = 0;
		var preAppendCount = 0;
		
		var tweetStack = {
			tweets : new Array()
		}
		
		var updateQueue = {
			tweets : new Array(),
			sinceID : options.sinceID
		}
    
        return this.each(function(){
        	if(options.tickerOnly == false){
        		tweetTicker = build();
        	} else{
        		tweetTicker = $('<div class="tweetticker"><div class="tweetticker-replace"></div></div>');
        	}
        	
        	$(this).append(tweetTicker);
        	
			tweetsList = $('<ul class="tweetticker-tweets-list"></ul>');
			overflowContainer = $('<div class="tweetticker-overflow-container"></div>');
			loading = $('<li class="tweetticker-loading"></li>');
        
			tweetTicker.find('div.tweetticker-username a').attr('href', 'http://twitter.com/'+options.username).html('@'+options.username);
			
			overflowContainer.wrapInner(tweetsList);

			tweetTicker.find('div.tweetticker-replace').replaceWith(overflowContainer);
			
			tweetsList.append(loading);
			
			initialize();
						
			$(window).resize(function(){
				updatePreAppendThreshhold();
			});
			
			tweetsList.mouseover(function(){
				currentRate = options.hoverRate;
			})
			
			tweetsList.mouseout(function(){
				currentRate = options.normalRate;
			}); 	
        });
        
		function initialize(){
			loading.text('Loading tweets...');
			
			$.jsonp({
				url : 'http://api.twitter.com/1/statuses/user_timeline.json?skip_user=true&screen_name='+options.username+'&count='+options.maxInitialTweets+'&since_id='+options.sinceID+'&callback=?',
				success : function(data){
					loading.remove();
					
					if(options.startOffScreen == true){
						tweetsList.css('left', overflowContainer.width());
					}
					
					var status;
					
			 		for (status = 0; status < data.length; status++){
			 			if(status == 0){
			 				options.sinceID = data[status].id;
			 				updateQueue.sinceID = options.sinceID;
			 			}
			 			
			 			var tweet = formatTweet(data[status]);
			 			
			 			tweetStack.tweets.unshift(tweet);
			 			tweetsList.append(tweet);
			 		}
			 		
			 		currentTweet = tweetsList.children('li.tweetticker-tweet').first();
			 		appendThreshhold = currentTweet.outerWidth(true) * -1;
			 		
			 		updatePreAppendThreshhold();

			 		currentRate = options.normalRate;
			 		
			 		if(options.liveUpdating == true){
			 			updateFlag = true;
			 		}
			 		
			 		failedFetchAttempts = 0;
		 			
		 			animationLoop();
			 	},
			 	error : function(XMLHttpRequest, textStatus){
			 		failedFetchAttempts++;
			 		
			 		setTimeout(function(){
				 		if(failedFetchAttempts < options.maxFailedFetchAttempts || options.maxFailedFetchAttempts == 0){
				 			if(textStatus == "error"){
				 				textStatus = "Error";
				 			}
				 			
				 			if(textStatus == "timeout"){
				 				textStatus = "Timeout";
				 			}
				 			
					 		loading.text(textStatus+' while attempting to load tweets. Trying again momentarily...');
				 			setTimeout(initialize, 5000);
				 		} else{
				 			loading.text('Failed to load tweets.');
				 		}
				 	}, 1000);
			 	}
			});
		}
		
		function animationLoop(){
			var currentPosition = parseInt(tweetsList.css('left').substr(0, tweetsList.css('left').length - 2));
			
			if(currentPosition < preAppendThreshhold){
				var tweetToAppend = tweetStack.tweets.pop();
				
				appendTweet(tweetToAppend);
				
				preAppendCount++;
			}
			
			if(currentPosition < appendThreshhold){
				var oldTweet = currentTweet;

				currentTweet = currentTweet.next('li.tweetticker-tweet');
				
				oldTweet.remove();
				
				if(preAppendCount > 0){
					var tweetToAppend = tweetStack.tweets.pop();
				
					appendTweet(tweetToAppend);
				} else{
					preAppendCount--;
					updatePreAppendThreshhold();
				}
				
				tweetsList.css('left', currentPosition - appendThreshhold+'px');

				appendThreshhold = currentTweet.outerWidth(true) * -1;
			}
			
			if(currentRate > 0){
				tweetsList.animate({'left':'-=1px'}, currentRate, 'linear', animationLoop);
			} else{
				animationLoop();
			}
			
			if(updateFlag == true){
				setTimeout(fetchUpdates, options.updateInterval);
			}
			
			updateFlag = false;
		}
		
		function fetchUpdates(){
			$.jsonp({
				url : 'http://api.twitter.com/1/statuses/user_timeline.json?skip_user=true&screen_name='+options.username+'&count='+options.maxTweetsPerUpdate+'&since_id='+updateQueue.sinceID+'&callback=?',
				success : function(data){
					var tempTweets = new Array();
					
					var status;
					
					for (status = 0; status < data.length; status++){
						if(status == 0){
		 					updateQueue.sinceID = data[status].id;
		 				}
					
			 			var tweet = formatTweet(data[status]);
			 			
			 			tempTweets.push(tweet);
		 			}
		 			
		 			var count = tempTweets.length;
		 			
		 			for(i = 0; i < count; i++){
		 				updateQueue.tweets.push(tempTweets.pop());
		 			}
		 			
		 			failedFetchAttempts = 0;
		 			
					updateFlag = true;
				},
				error : function(XMLHttpRequest, textStatus){
					failedFetchAttempts++;
				},
				complete : function(){
					if(failedFetchAttempts < options.maxFailedFetchAttempts || options.maxFailedFetchAttempts == 0){
						updateFlag = true;
					}
				}
			});
		}
		
		function appendTweet(appendingTweet){
			if(parseInt($(appendingTweet).attr('id')) == options.sinceID){
				if(updateQueue.tweets.length > 0){
					var count = updateQueue.tweets.length;
					for(i = 0; i < count; i++){
						var tweet = updateQueue.tweets.pop()
						
						tweetStack.tweets.unshift(tweet);
						tweetsList.append(tweet);
					}	
									
					options.sinceID = updateQueue.sinceID;
				}
			}
			
			tweetStack.tweets.unshift(appendingTweet);
			tweetsList.append(appendingTweet);
			
			updatePreAppendThreshhold();
		}

		function updatePreAppendThreshhold(){
			preAppendThreshhold = overflowContainer.width() - tweetsList.width();
		}
		
		function formatTweet(data){
			var date = Date.parse(data.created_at);
 			var tweetText = data.text;
 			
 			date = date.addMinutes(-1 * date.getTimezoneOffset()).toString(options.dateFormat);
 			
 			dateText = '<span class="tweetticker-date">'+date+'</span>';
 			
 			tweetText = tweetText.replace(/http([s]?):\/\/([^\ \)$]*)/g, '<a href="http$1://$2" rel="nofollow">http$1://$2</a>');
 			tweetText = tweetText.replace(/(^|)@([A-Za-z0-9_]+)/g, '<a href="http://twitter.com/$2" rel="nofollow">@$2</a>');
 			tweetText = tweetText.replace(/\#([a-zA-Z0-9_]*)/g, '<a href="http://search.twitter.com/?q=%23$1" rel="nofollow">\#$1</a>');
 			
 			return '<li class="tweetticker-tweet" id="'+data.id+'">'+dateText+tweetText+'</li>';
		}
		
	    function build(){
			var build;
			
			build += '<div class="tweetticker">';
			build += '<div class="tweetticker-container">';
			build += '<div class="tweetticker-container-left"></div>';
			build += '<div class="tweetticker-container-content">';
			build += '<div class="tweetticker-username"><a href="#">@username</a></div>';
			build += '<div class="tweetticker-twitter-link"><a href="http://twitter.com">Twitter</a></div>';
			build += '<div class="tweetticker-tweetbox">';
			build += '<div class="tweetticker-tweetbox-left"></div>';
			build += '<div class="tweetticker-tweetbox-right"></div>';
			build += '<div class="tweetticker-tweetbox-content">';
			build += '<div class="tweetticker-replace"></div>';
			build += '</div>';
			build += '</div>';
			build += '</div>';
			build += '<div class="tweetticker-container-right"></div>';
			build += '</div>';
			build += '</div>';
			
			return $(build);
		}
    };

    $.fn.tweetTicker.defaults = {
		username : 'twitter',
		maxInitialTweets : 20,
		maxTweetsPerUpdate: 20,
		normalRate : 25,
		hoverRate : 100,
		sinceID : 1,
		startOffScreen : true,
		liveUpdating : true,
		updateInterval : 15000,
		maxFailedFetchAttempts : 5,
		dateFormat : 'dd/MM/yyyy h:mm tt',
		tickerOnly : false
    };
          
})(jQuery);
