var Twitter = (function () {
    var Twitter = {};

    Twitter.Tweet = new Class({
        /** Tweet - A Tweet that was twut on twitter */
        'initialize': function init (id, screenName, createdAt, text, reply) {
            this.id = id;
            this.screenName = screenName;
            this.reply = reply;
            this.text = text;
            this.createdAt = Date.parse(datefix(createdAt));
        },

        /** toElement - Renders an HTML Element */
        toElement: function toElement () {
            if (!('element' in this)) {
                this.element = new Element('div', {
                    'class': "tweet"
                }).adopt(
                    tweetBody(this.text),

                    new Element('a', {
                        'class': 'date',
                        'href': "http://twitter.com/{screenName}/statuses/{id}".substitute(this),
                        'text': this.createdAt.timeDiffInWords()
                    })
                );

                if (this.reply) {
                    this.element.grab(
                        new Element('a', {
                            'class': 'reply',
                            'href': "http://twitter.com/{screenName}/statuses/{statusID}".substitute(this.reply),
                            'text': "in reply to @{screenName}".substitute(this.reply)
                        }));
                }
            }

            return this.element;
        }
    });

    Twitter.Tweet.fromHash = function (h) {
        var reply = h.get('in_reply_to_status_id') ? {
            'screenName': h.get('in_reply_to_screen_name'),
            'userID':     h.get('in_reply_to_user_id'),
            'statusID':   h.get('in_reply_to_status_id')
        } : null ;

        return new Twitter.Tweet(
            h.get('id'), h.get('user').screen_name,
            h.get('created_at'), h.get('text'), reply
        );
    };

    Twitter.Timeline = new Class({
        /** One user's twitter timeline */
        'Implements': [Options, Events],
        'initialize': function (username, options) {
            this.setOptions(options);
            this.username = username;
            this.userData = null;
            this.latest = null;
            this.tweets = [];
            this.request = new Request.JSONP({
                method: 'get',
                url: "http://twitter.com/statuses/user_timeline.json",
                onComplete: this.addData.bind(this)
            });

            if (this.options.updateOnStart) {
                this.update();
            }

            if (this.options.updatePeriod) {
                this.update.periodical(this.options.updatePeriod, this);
            }
        },

        'options': {
    	    'count': 10,
            'updateOnStart': true,
            'updatePeriod': 60000
            // onUpdate: $empty
        },

        /**
         * get the next n tweets (since this.latest)
         * add them to this.tweets and fire the update event
         */
        'update': function (n) {
            var data = {
                'screen_name': this.username,
                'count': n || this.options.count
            };

            if (this.latest != null) {
                data = $extend(data, {'since_id': this.latest });
            }

            // when this request comes back it calls addData
            // to update the timeline
            this.request.send({data: data}); 

            return this;
        },

        'addData': function (data) {
            var newTweets = $splat(data).map(
                function (d) {
                    return Twitter.Tweet.fromHash($H(d));
                });

            if (!this.userData && data.length) {
                this.userData = $H($H(data[0]).get('user'));
                Twitter.userData.set(this.userData.get('screen_name'),
                                     this.userData);
                this.fireEvent('userDataLoaded', this);
            }

            this.tweets = newTweets.extend(this.tweets);
            this.latest = $H(newTweets[0]).get('id');
            this.fireEvent('update', [this, newTweets]);
        },

        'toElement': function () {
            var element = new Element('div', {
                'class': 'twitterStream'
            }).adopt(this.tweets);

            this.addEvent('update', function (tweets, newTweets) {
                element.adopt(newTweets);
            });

            return element;
        }
    });

    Twitter.userData = $H();

    function tweetBody(text) {
        var linkify = function (str) {
            /** linkify makes @mentions, #tags and urls into links */
            return str
                .replace(/(\s|^)(mailto\:|(news|(ht|f)tp(s?))\:\/\/\S+)/g,'$1<a href="$2">$2</a>')
                .replace(/(\s|^)@(\w+)/g, '$1<a href="http://twitter.com/$2">@$2</a>')
                .replace(/(\s|^)#(\w+)/g, '$1<a href="http://twitter.com/search?q=%23$2">#$2</a>');
        };

        var element = new Element('p', {
            'class': 'tweetBody',
            'html': linkify(text)
        });

        return element;
    }


    function datefix (datestring) {
        /* Twitter seems to give some wacky date format
         * that IE can't handle, so I just move some sh*t around */
        return  datestring.replace(/^(.+) ((?:\+|-)\d+) (\d+)$/, "$1 $3 GMT$2");
    };

    return Twitter;
}());
