(function($) {
    
    var settings = {
        query : 'twitter',
        rpp : 20, // returns per page
        showAvatar : true,
        avatarSize : 48,
        listId : 'twitter_list',
        refresh : 30000,
        refresh_url : '',
        firstRun : true
    };
    
    $.fn.twitterFeed = function(options) {
        if (options) {
            $.extend(settings, options);
        }
        return this.each(function() {
            twitterFeed(this);
        });
    };
    
    function twitterFeed(container) {
        connectToTwitter(container);
        
        if (settings.refresh) {
            setTimeout((function() {
                twitterFeed(container);
            }), settings.refresh);
        }
    }
        
    function connectToTwitter(container) {
        var url = 'http://search.twitter.com/search.json';
        if (settings.refreshUrl) {
            url += settings.refreshUrl;
        } else {
            url += '?q=' + encodeURIComponent(settings.query) + '&rpp=' + settings.rpp;
        }
        // console.log(url);
        
        $.ajax({
            url : url,
            dataType : 'jsonp',
            type : 'GET',
            timeout : 5000,
            error : function() {
                $(container).html('Unable to retrieve Twitter feed.');
            },
            success : function(json) {
                if (!!!json.results) {
                    // console.log(Dumper(json));
                    return;
                }
                
                $.each(json.results, function(i, item) {
                    if (i < 0) return;
                    if (i == 0) {
                        $('<ul></ul>').attr('id', settings.listId).prependTo(container);
                    }
                    
                    var createdAt = settings.refresh ? localTime(item.created_at) : relativeTime(item.created_at);
                    var itemHtml = '';
                    if (settings.showAvatar) {
                        itemHtml = '<div class="img"><a href="http://twitter.com/' + item.from_user + '/"><img src="' + item.profile_image_url + '" height="' + settings.avatarSize + '" width="' + settings.avatarSize + '" alt="' + item.from_user + '" title="' + item.from_user + '" /></a></div>';
                    }
                    itemHtml += '<div class="txt"><span class="msg"><a class="user" href="http://twitter.com/' + item.from_user + '/">' + item.from_user + '</a>: ' + formatText(item.text) + '</span><br />';
                    
                    itemHtml += '<span class="footer"><span class="date">' + createdAt + '</span>';
                    itemHtml += ' (<a href="http://twitter.com/home?status=%40' + item.from_user + '%20&in_reply_to_status_id=' + item.id + '&in_reply_to=' + item.from_user + '">Reply</a>)';
                    itemHtml += ' (<a href="http://twitter.com/home?status=RT%20%40' + item.from_user + '%20' + encodeURIComponent(item.text) + '&in_reply_to_status_id=' + item.id + '&in_reply_to=' + item.from_user + '">RT</a>)';
                    itemHtml += '</span></div>';
                    
                    $('<li></li>').attr('id', item.id).addClass('clearfix').html(itemHtml).appendTo('#' + settings.listId);
                    
                    if (!settings.firstRun) {
                        $('#' + item.id).hide().fadeIn(2000);
                    }
                });
            
                if (settings.refresh) {    
                    if ($('#' + settings.listId + ' li').length > settings.rpp) {
                        $('#' + settings.listId + ' li').each(function(i) {
                            if (i >= settings.rpp) {
                                $(this).fadeOut(2000);
                            }
                        });
                    }
                }
                
                $('#' + settings.listId + ' li a').attr('target', '_new');

                settings.firstRun = false;
                settings.refreshUrl = json.refresh_url;
            }
        });
    }
    
    function formatText(txt) {
        var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
        txt = txt.replace(exp, '<a href="$1" class="external">$1</a>');
        exp = /[\@]+([A-Za-z0-9-_]+)/ig;
        txt = txt.replace(exp, '<a href="http://twitter.com/$1" class="profile">@$1</a>');
        exp = /[\#]+([A-Za-z0-9-_]+)/ig;
        
        return txt;
    }
    
    function relativeTime(dateStr) {
        var dt = Date.parse(dateStr);
        var relativeTo = (arguments.length > 1) ? arguments[1] : new Date();
        var delta = parseInt((relativeTo.getTime() - dt) / 1000);

        if (delta < 60) {
            return 'less than a minute ago';
        } else if (delta < 120) {
            return 'about a minute ago';
        } else if (delta < (55*60)) {
            return (parseInt(delta / 60)).toString() + ' minutes ago';
        } else if (delta < (1.6*60*60)) {
            return 'about an hour ago';
        } else if (delta < (24*60*60)) {
            return 'about ' + (Math.round(delta / 3600)).toString() + ' hours ago';
        } else if (delta < (48*60*60)) {
            return '1 day ago';
        } else {
            return (parseInt(delta / 86400)).toString() + ' days ago';
        }
    }
    
    function localTime(dateStr) {
        var dt = new Date(Date.parse(dateStr));
        return dt.toLocaleString();
    }
    
}) (jQuery);