ONSUGAR = window.ONSUGAR || {};

(function() {
    if (ONSUGAR.TwitterWidget) {
        return;
    }

    Array.prototype.eachi = function(fn) {
        for (var i = 0; i < this.length; i++) {
            fn.call(this[i], i);
        }
        return this;
    }

    String.prototype.escapeHTML = function () {
        return(
            this.replace(/&/g,'&amp;').
            replace(/>/g,'&gt;').
            replace(/</g,'&lt;').
            replace(/"/g,'&quot;')
        );
    };

    var API_BASE_URL = 'http://api.twitter.com/1/statuses/user_timeline.json';

    var buildQueryString = function(params) {
        var query = [];
        for ( key in params ) {
            if ( params.hasOwnProperty(key) ) {
                query.push(key + "=" + encodeURIComponent(params[key]));
            }
        }
        return query.join('&');
    }

    /*
    * From : http://webdesign.onyou.ch/2010/08/04/javascript-time-ago-pretty-date/
    */
    function timeAgo(date_str) {
        var time_formats = [
        [60, 'just now', 1], // 60
        [120, '1 minute ago', '1 minute from now'], // 60*2
        [3600, 'minutes', 60], // 60*60, 60
        [7200, '1 hour ago', '1 hour from now'], // 60*60*2
        [86400, 'hours', 3600], // 60*60*24, 60*60
        [172800, 'yesterday', 'tomorrow'], // 60*60*24*2
        [604800, 'days', 86400], // 60*60*24*7, 60*60*24
        [1209600, 'last week', 'next week'], // 60*60*24*7*4*2
        [2419200, 'weeks', 604800], // 60*60*24*7*4, 60*60*24*7
        [4838400, 'last month', 'next month'], // 60*60*24*7*4*2
        [29030400, 'months', 2419200], // 60*60*24*7*4*12, 60*60*24*7*4
        [58060800, 'last year', 'next year'], // 60*60*24*7*4*12*2
        [2903040000, 'years', 29030400], // 60*60*24*7*4*12*100, 60*60*24*7*4*12
        [5806080000, 'last century', 'next century'], // 60*60*24*7*4*12*100*2
        [58060800000, 'centuries', 2903040000] // 60*60*24*7*4*12*100*20, 60*60*24*7*4*12*100
        ];

        var seconds = (new Date() - new Date(date_str)) / 1000;
        var token = 'ago', list_choice = 1;
        if (seconds < 0) {
            seconds = Math.abs(seconds);
            token = 'from now';
            list_choice = 2;
        }
        var i = 0, format;
        while (format = time_formats[i++]) {
            if (seconds < format[0]) {
                if (typeof format[2] == 'string') {
                    return format[list_choice];
                } else {
                    return Math.floor(seconds / format[2]) + ' ' + format[1] + ' ' + token;
                }
            }
        }
        return date_str;
    };


    /*
     * Humbly adapted from : https://gist.github.com/442463
     *
     * See the documentation here: http://dev.twitter.com/pages/tweet_entities
     * Basically, add ?include_entities=true to your timeline call
     *
     * Copyright 2010, Wade Simmons
     * Licensed under the MIT license
     * http://wades.im/mons
     *
     */
    function linkifyEntities(tweet) {
        if (!(tweet.entities)) {
            return tweet.text;
        }

        // This is very naive, should find a better way to parse this
        var index_map = {}

        tweet.entities.urls.eachi(function(i) {
            var that = this;
            index_map[this.indices[0]] = [this.indices[1], function(text) {return "<a target='_blank' href='"+that.url.escapeHTML()+"'>"+text.escapeHTML()+"</a>"}];
        });

        tweet.entities.hashtags.eachi(function(i) {
            var that = this;
            index_map[this.indices[0]] = [this.indices[1], function(text) {return "<a target='_blank' href='http://twitter.com/search?q="+escape("#"+that.text)+"'>"+text.escapeHTML()+"</a>"}];
        })

        tweet.entities.user_mentions.eachi(function(i) {
            var that = this;
            index_map[this.indices[0]] = [this.indices[1], function(text) {return "<a target='_blank' title='"+that.name.escapeHTML()+"' href='http://twitter.com/"+that.screen_name.escapeHTML()+"'>"+text.escapeHTML()+"</a>"}];
        })

        var result = "";
        var last_i = 0;
        var i = 0;

        // iterate through the string looking for matches in the index_map
        for (i=0; i < tweet.text.length; ++i) {
            var ind = index_map[i];
            if (ind) {
                var end = ind[0];
                var func = ind[1];
                if (i > last_i) {
                    result += tweet.text.substring(last_i, i).escapeHTML();
                }
                result += func(tweet.text.substring(i, end));
                i = end - 1;
                last_i = end;
            }
        }

        if (i > last_i) {
            result += tweet.text.substring(last_i, i).escapeHTML();
        }

        return result;
    }

    function Tweet(tweet) {
          var html = '<span>' + linkifyEntities(tweet) + '</span>\
              <div class="meta">\
                <a target="_blank" href="http://www.twitter.com/' + tweet.user.screen_name + '/status/' + tweet.id_str + '" class="date">' + timeAgo(tweet.created_at) + '</a>\
              </div>';

          var li = document.createElement('li');

          li.id = 'tweet-' + tweet.id_str;
          li.innerHTML = html;

          this.element = li;
    }

    ONSUGAR.TwitterWidget = function(opts) {
        this.init(opts);
    }

    ONSUGAR.TwitterWidget.WIDGET_NUMBER = 0;

    ONSUGAR.TwitterWidget.jsonP = function(url, params) {
        var script = document.createElement('script');
        var head = document.getElementsByTagName('head')[0];

        params = params || {};
        query = buildQueryString(params);
        url += '?' + query;

        script.type = 'text/javascript';
        script.src = url;
        head.insertBefore(script, head.firstChild)
        return script;
    };


    ONSUGAR.TwitterWidget.prototype = function() {
        return {
            init: function(opts) {
                this.nid = opts.nid;
                this.count = opts.count || 2;
                this.screen_name = opts.screen_name || null;
                this.widget_num = ONSUGAR.TwitterWidget.WIDGET_NUMBER++;
                this.callback_function = 'receive_callback_' + this.widget_num;
                this.full_callback_function = 'ONSUGAR.TwitterWidget.' + this.callback_function;

                var that = this;
                ONSUGAR.TwitterWidget[this.callback_function] = function(response) {
                    that.renderTweets(response);
                }

                this._initContainer();
                this.fetchTweets();
            },

            fetchTweets: function() {
                ONSUGAR.TwitterWidget.jsonP(API_BASE_URL, {
                    'screen_name': this.screen_name,
                    'count': this.count,
                    'callback': this.full_callback_function,
                    'include_entities': true
                });
            },

            renderTweets: function(tweets) {
                var el = document.getElementById('twitter-widget-' + this.widget_num);


                var that = this;

                tweets.eachi(function () {
                    el.appendChild((new Tweet(this, that.showFaces, that.skin)).element);
                });

            },

            _initContainer: function() {
                var html = "<ul class='normal' id='twitter-widget-" + this.widget_num + "'></ul>";
                document.write(html);
            }
        }
    }();
})();

