﻿/**
* Twitter status and search plugin
*
* @version	1.1
* @changlog 1.1
- fixed duplicate tweet bug for first refresh of search
- added mouse events to stop/start search timer for polling searches
* @author	Jasal Vadgama for Live Nation UK
* @require	jquery
jquery.jsonp - http://jquery-jsonp.googlecode.com/files/jquery.jsonp-1.0.4.min.js
* @license	GPL v3
**/

(function($) {
    $.fn.twitterfeed = function(settings) {
        var config = {
            user: "", 						    // username for the timeline feed
            timelineContainer: "", 			    // container class/id for the timeline
            userTweetCount: 1, 				    // number of user tweets to show

            hashtag: "", 					    // hastag/search term for search feed
            searchContainer: "", 			    // container class/id for the search
            searchTweetCount: 5, 			    // number of search tweets to show
            autoUpdateSearch: false, 		    // set whether to update search results
            autoUpdateSearchInterval: 30000,    // how long to wait between updates

            retweet: true,                     // show a retweet link

            requestTimeout: 5000, 			    // how long to wait before throwing a timeout error
            errorMessage: "No tweets to show"	// custom error message
        };

        var vars = {
            timelineJSON: "", 				    // JSON url for user timeline
            searchJSON: "", 					// JSON url for search
            latestSearchId: 0					// most recent search result
        };

        if (settings) $.extend(config, settings);

        function addLatestTweet(twitter) {
            config.timelineJSON = "http://search.twitter.com/search.json?callback=?&from=" + config.user + "&rpp=" + config.userTweetCount;

            counter = 1;

            $.jsonp({
                url: config.timelineJSON,
                data: {},
                dataType: "jsonp",
                timeout: config.requestTimeout,
                success: function(data, status) {
                    if (data.results.length > 0) {
                        // remove "loading..."
                        $(twitter).find(config.timelineContainer).html("");

                        $.each(data.results, function(i, item) {
                            // tidy links in tweet
                            tweet = linkifyTweet(item.text);

                            // get real time values
                            var values = item.created_at.split(" ");
                            time_value = values[2] + " " + values[1] + ", " + values[3] + " " + values[4];
                            tweetDate = getRelTime(time_value);

                            // bug fix - make sure links show as links and not text
                            tweetMethod = item.source.replace(/(&quot;)/g, "\"").replace(/(&lt;)/g, "<").replace(/(&gt;)/g, ">");

                            // add class to even items
                            if (counter % 2 == 0)
                                tweetClass = " class='even'";
                            else
                                tweetClass = "";

                            counter++;

                            // add tweet to page
                            tweetContainer = $("<li" + tweetClass + "><p><a href='http://www.twitter.com/" + item.from_user + "' title=''>" + item.from_user + ":</a> " + tweet + "</p>").appendTo($(twitter).find(config.timelineContainer));

                            // add retweet
                            if (config.retweet) {
                                encodedTweet = escape(item.text);
                                $("<a href='http://twitter.com/home?status=RT%20@" + config.user + "%20" + encodedTweet + "' title='Retweet this tweet' target='_blank' class='retweet'>re-tweet</a>").appendTo($(tweetContainer));
                            }

                            // ie redraw fix
                            if (BrowserDetect.browser == "Explorer" && BrowserDetect.version < 8)
                                $(twitter).next().css("bottom", "5px");
                        });
                    } else {
                        // no tweets - show error message
                        $(twitter).find(config.timelineContainer).html("<p>" + config.errorMessage + "</p>");
                    }
                },
                error: function(XHR, textStatus, errorThrown) {
                    // request error - show error message
                    $(twitter).find(config.timelineContainer).html("<p>" + config.errorMessage + "</p>");
                }
            });
        };

        function addSearch(twitter) {
            config.searchJSON = "http://search.twitter.com/search.json?callback=?&q=" + config.hashtag;

            // url encode any #s and @s in the config.hashtag
            config.searchJSON = config.searchJSON.replace(/(@)/g, '%40').replace(/(#)/g, '%23');

            $.jsonp({
                url: config.searchJSON + "&rpp=" + config.searchTweetCount,
                data: {},
                dataType: "jsonp",
                timeout: config.requestTimeout,
                success: function(data, status) {
                    if (data.results.length > 0) {
                        // remove "loading..."
                        $(twitter).find(config.searchContainer).html("");

                        vars.tweetCounter++;

                        $.each(data.results, function(i, item) {
                            // set most recent search id
                            if (i == 0)
                                vars.latestSearchId = item.id;

                            // tidy links in tweet
                            tweet = linkifyTweet(item.text);

                            // get real time values
                            var values = item.created_at.split(" ");
                            time_value = values[2] + " " + values[1] + ", " + values[3] + " " + values[4];
                            tweetDate = getRelTime(time_value);

                            // bug fix - make sure links show as links and not text
                            tweetMethod = item.source.replace(/(&quot;)/g, "\"").replace(/(&lt;)/g, "<").replace(/(&gt;)/g, ">");

                            // add tweet to page
                            $(twitter).find(config.searchContainer).append("<article><img src='" + item.profile_image_url + "' alt='' /><p><a href='http://www.twitter.com/" + item.from_user + "' title='' class='t_user'>" + item.from_user + ":</a> " + tweet + "</p></article>");
                        });

                        // start polling search results
                        if (config.hashtag && config.autoUpdateSearch) {
                            cInterval = window.setInterval(function() { pollSearches(twitter); }, config.autoUpdateSearchInterval);

                            $(twitter).find(config.searchContainer).mouseenter(function() {
                                window.clearInterval(cInterval);
                            }).mouseleave(function() {
                                cInterval = window.setInterval(function() { pollSearches(twitter); }, config.autoUpdateSearchInterval);
                            });
                        }
                    } else {
                        // no tweets - show error message
                        $(twitter).find(config.searchContainer + " article").html("<p>" + config.errorMessage + "</p>");
                    }
                },
                error: function(XHR, textStatus, errorThrown) {
                    // request error - show error message
                    $(twitter).find(config.searchContainer + " article").html("<p>" + config.errorMessage + "</p>");

                }
            });
        };

        function pollSearches(twitter) {
            $.jsonp({
                url: config.searchJSON + "&result_type=recent&since_id=" + vars.latestSearchId + "&rpp=1",
                data: {},
                dataType: "jsonp",
                timeout: config.requestTimeout,
                success: function(data, status) {
                    if (data.results.length > 0) {
                        $.each(data.results, function(i, item) {
                            if (vars.latestSearchId != item.id) {
                                // set most recent search id
                                vars.latestSearchId = item.id;

                                // tidy links in tweet
                                tweet = linkifyTweet(item.text);

                                // get real time values
                                var values = item.created_at.split(" ");
                                time_value = values[2] + " " + values[1] + ", " + values[3] + " " + values[4];
                                tweetDate = getRelTime(time_value);

                                // bug fix - make sure links show as links and not text
                                tweetMethod = item.source.replace(/(&quot;)/g, "\"").replace(/(&lt;)/g, "<").replace(/(&gt;)/g, ">");

                                tweetHTML = $("<article></article>").html("<img src='" + item.profile_image_url + "' alt='' /><p><a href='http://www.twitter.com/" + item.from_user + "' title='' class='t_user'>" + item.from_user + ":</a> " + tweet + "</p><aside><p>" + tweetDate + " from " + tweetMethod + "</p></aside>").fadeTo(1, 0);

                                // add tweet to page
                                $(twitter).find(config.searchContainer).prepend(tweetHTML);

                                // show new tweet
                                $(tweetHTML).css({ marginTop: "-" + $(tweetHTML).height() + "px" }).animate({ marginTop: "0px" }).fadeTo(1000, 1, function() {
                                    // remove last tweet
                                    $(twitter).find("article:last").remove();
                                });
                            }
                        });
                    }
                },
                error: function(XHR, textStatus, errorThrown) {
                    // do nothing
                }
            });
        };

        function linkifyTweet(text) {
            // finds all @'s, hastags and links and converts to markup
            tweet = text.replace(/http:\/\/\S+/g, '<a href="$&" target="_blank">$&</a>')
						.replace(/(@)(\w+)/g, ' <a href="http://twitter.com/$2" target="_blank">@$2</a>')
						.replace(/(#)(\w+)/g, ' <a href="http://search.twitter.com/search?q=%23$2" target="_blank" class="by">#$2</a>');
            return tweet;
        };

        function getRelTime(time_value) {
            // sets relative time from tweet post
            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 'less than a minute ago';
            else if (delta < 120)
                return 'about a minute ago';
            else if (delta < (60 * 60))
                return (parseInt(delta / 60)).toString() + ' minutes ago';
            else if (delta < (120 * 60))
                return 'about an hour ago';
            else if (delta < (24 * 60 * 60))
                return 'about ' + (parseInt(delta / 3600)).toString() + ' hours ago';
            else if (delta < (48 * 60 * 60))
                return '1 day ago';
            else
                return (parseInt(delta / 86400)).toString() + ' days ago';
        };

        // get latest tweets
        if (config.user && config.timelineContainer)
            addLatestTweet(this);

        // get search results
        if (config.hashtag && config.searchContainer)
            addSearch(this);
    };
})(jQuery);
