﻿// jTweetr
// Developed By: SyntaxC4
// jTweetr brings Twitter to your website in a CSS friendly way.

// History
// R2 - Fixed Bugs when adding multiple feeds on one page.

// Determines what type of Search Query to Build.
var TweetTypes = {
    "Search": 1,
    "From": 2,
    "To": 3,
    "Mention": 4,
    "SearchHash": 5,
    "AppFilter": 6
};

// Enumerator of Loading Message Type
var LoadingType = {
    "Text": 0,
    "Image": 1
};

(function($) {

    var settings;
    var count = 0;
    var prefix = 'jt$';

    // Array of Query Strings for the Search API
    var APIUrls = [
    'http://search.twitter.com/search.json?q=',
    '',
    'from%3A',
    'to%3A',
    '%40',
    '%23',
    'landing+source%3A'
    ];

    // Builds the Twitter Search Query Url.
    BuildUrl = function(SearchMethod, sQuery) {

        var strUrl = '';

        strUrl += APIUrls[0].toString();
        strUrl += APIUrls[SearchMethod].toString();
        strUrl += UrlFriendly(sQuery);

        switch (SearchMethod) {
            case TweetTypes.Search:
                // set the language of the Search
                var searchLang = '&lang=' + ((settings.Language.length > 0 & settings.Language.length === 2) ? settings.Language : "en");
                strUrl += searchLang.toString();
                break;
        }
        // rpp is the number of Results to yield.
        strUrl += '&rpp=' + settings.NumResults.toString();
        return strUrl;
    }

    // Clears the Container of all of it's HTML
    ClearTweets = function(container, NumToLeave) {
        if (arguments.length === 1)
            container.html('');
        else {
            //TODO: Add Code to Remove All but NumToLeave Items. 
        }
    }

    // Determines and outputs the appropriate Loading Message/Image
    DisplayLoadingMessage = function(container) {
        switch (settings.LoadType) {
            case LoadingType.Image:
                $("<img></img>").attr('src', settings.LoadObj).appendTo(container);
                break;
            case LoadingType.Text:
                container.html("<p>"+settings.LoadObj+"</p>");
                break;
        }
    }

    FormatText = function(text, sQuery) {
        //Create link
        var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
        text = text.replace(exp, "<a href='$1' class='" + settings.LinkClass + "'>$1</a>");
        //Link User to Profile
        var exp = /[\@]+([A-Za-z0-9-_]+)/ig;
        text = text.replace(exp, "<a href='http://twitter.com/$1' class='" + settings.ProfileClass + "'>@$1</a>");
        //Bold Search Text
        if (settings.SearchType === TweetTypes.Search) {
            var arrQuery = sQuery.split(",");
            $.each(arrQuery, function(i, item) {
                var regEx = eval('/' + item + '/ig');
                var strBold = new String('<strong>' + item + '</strong>');
                text = text.replace(regEx, strBold);
            });
        }
        return text;
    }

    GenerateID = function() {
        return prefix + count++;
    }

    LastGeneratedID = function() {
        return prefix + count - 1;
    }

    RequestTwitterSearch = function(container, url) {
        $.ajax({ url: url,
            type: 'GET',
            dataType: 'jsonp',
            timeout: 1000,
            error: function() {
                container.html("<p>" + settings.LoadError + "</p>");
            },
            // Takes the JSON that is returned from the Search Query and Builds the HTML for our page.
            success: function(data) {
                var list;
                var listChildren = '';
                if (data !== null || data !== 'undefined') {
                    ClearTweets(container);
                    $.each(data.results, function(i, item) {
                        if (i === 0) {
                            list = $("<dl></dl>").attr('id', GenerateID()).attr('class', settings.ListClass).prependTo(container);
                            listChildren = $("<dt></dt>").attr('class', settings.TitleClass).html(Substitute(settings.Title, StripQuery(data.query))).prependTo(LastGeneratedID());
                        }
                        if (item !== 'undefined') {
                            var renderHtml = "<a href='http://www.twitter.com/" + item.from_user + "'><img src='" + item.profile_image_url + "' alt='" + item.from_user + "' class='" + settings.AvatarClass + "' /></a> <div class='" + settings.TweetClass + "'>" + FormatText(item.text, StripQuery(data.query)) + "</div>";
                            listChildren.append($("<dd></dd>").attr('class', settings.TweetConClass + ' ' + ((i % 2 === 0) ? settings.EvenClass : settings.OddClass)).html(renderHtml).prependTo(LastGeneratedID()));
                        }
                    });
                    if (list !== 'undefined' && listChildren !== 'undefined') {
                        list.html(listChildren);
                    }
                }
                else {
                    container.html("<p>" + settings.LoadError + "</p>");
                }
            }
        });
    }

    StripQuery = function(sQuery) {
        var regEx = '';
        for (i = 1; i <= APIUrls.length; i++) {
            regEx = eval('/' + APIUrls[i] + '/');
            sQuery = sQuery.replace(regEx, '');
        }
        return sQuery;
    }

    Substitute = function(text, sQuery) {
        return text.replace(/\[Query\]/, sQuery);
    }

    // Makes the Query Parameters Twitter Expected Url Encoded
    UrlFriendly = function(sQuery) {
        if (sQuery.search(/,/) > 0)
            return "ors=" + sQuery.replace(/,/g, "+");
        else
            return sQuery;
    }

    ValidateSettings = function() {

        // Twitter will ban Scripts running more than once per minute.
        if (settings.FeedRefresh < 60)
            settings.FeedRefresh = 60;

        // Stops the script from displaying the path to the image if the LoadType wasn't changed.
        if (settings.LoadType === LoadingType.Text && settings.LoadObj.substring(0, 4) === 'http')
            settings.LoadObj = 'Loading Tweets...';
    }

    // The jTweetr Extension. Calling this like $("TwitterBox").jTweetr("CTTDNUG")
    // Will create a listing of Tweets containing the #CTTDNUG Hashtag.
    $.fn.jTweetr = function(Query, customSettings) {
        return this.each(function() {
            var container = $(this);

            settings = $.extend({
                // Determines which Query String to user against the Search API
                SearchType: TweetTypes.SearchHash,
                // Title the Results. [Query] is replaced by contents of Query.
                Title: '[Query] Tweets',
                // CSS Style-name Overrides
                ListClass: 'TweetsList',
                TitleClass: 'TweetsTitle',
                TweetConClass: 'TweetContainer',
                TweetClass: 'Tweet',
                AvatarClass: 'TwitAvatar',
                ProfileClass: 'TwitProfile',
                LinkClass: 'ExternalLink',
                EvenClass: 'even',
                OddClass: 'odd',
                // Loading Message/Image is displayed while Query is in progress
                LoadType: LoadingType.Text,
                // LoadingType.Text 'Loading...' || LoadingType.Image 'pathToFile/Image.gif'
                LoadObj: '<p>Loading Tweets...</p>',
                LoadError: 'Error Loading Tweets.',
                // Number of Results to bring
                NumResults: 20,
                // Number of Seconds to Refresh the Feed. Must be >= 60.
                FeedRefresh: 60,
                Language: 'en'
            }, customSettings);

            // Puts the Loading Message/Image to the Container
            DisplayLoadingMessage(container);

            ValidateSettings();

            // Builds the Twitter Search Query Url
            var url = BuildUrl(settings.SearchType, Query);

            // Posts Query to Twitter for JSON Results
            RequestTwitterSearch(container, url);

            // Update Page every FeedRefesh Seconds
            setInterval(function() { RequestTwitterSearch(container, url) }, settings.FeedRefresh * 1000);
        });
    }
})(jQuery);