//twtplus 0.5 for ubiq 0.5+
//*Shorten all urls in a post
//*d or @ message with friend username autocompletion
//*Post as specified user using "as" modifier
//Visit for more explanation: http://damienh.org/2009/03/02/twtplus-the-missing-twitter-command-for-ubiquity-and-firefox/
//With improvements from Kate Rhodes http://gist.github.com/73728
 
twitter_template = "\
<div style=\"overflow: auto; height: 450px;\"> \
{for entry in entries} \
  <div style=\"margin:0;padding:2px;padding-left:4px;background-color:{if entry_index%2 == 0}#555{else}#313131{/if};border:solid 1px;border-top-color:#484848;border-left:solid 3px #ccc;border-right-color:#2c2c2c;border-bottom-color:#2b2b2b;font-size:13px;-moz-border-radius:5px;\"> \
<a href=\"http://twitter.com/home?in_reply_to=${entry.user.screen_name}&in_reply_to_status_id=${entry.id}&status=%40${entry.user.screen_name}+\" ><img src=\"${entry.user.profile_image_url}\" style=\"height: 2em; float: left;margin-right:3px; margin-top:4px;border:none;\"/></a> \
  <span style=\"font-weight: bold\">${entry.user.screen_name}</span> \
  <span>${entry.text}</span> \
<div style=\"clear:both;\"></div> \
</div> \
{/for}</div>"; 
const STATUS_MAXLEN = 140;
var store = Application.storage;
var prefs = Application.prefs;
const TWT_PREFIX = "ubiquity_twitter_plus";
const TWT_TIMELINE = TWT_PREFIX+"_timeline";
const TWT_TIMELINE_DATE = TWT_PREFIX+"_timeline_date";
const TWT_CUR_LOGIN = TWT_PREFIX+"_cur_login";
var $j = jQuery;
var log = CmdUtils.log;
 
function setCurLogin(login){
    store.set(TWT_CUR_LOGIN, login);
}
function getCurLogin(){
    var login = store.get(TWT_CUR_LOGIN, '');
    if(!login){
        logins = getTwitterIds();
        if(logins.length > 0){
            login = logins[0];
            setCurLogin(login);
        }
    }
    return login;
}
function get_twitter_friends(callback) {
    var curLogin = getCurLogin();
    $j.ajax({
        url: "http://twitter.com/statuses/friends.json",
        type: "GET",
        dataType: "json",
		username: curLogin ? curLogin.username : '',
		password: curLogin ? curLogin.password : '',
        success: function(data) {
            var friends = [];
            for (var i in data) {
                var friend = data[i];
                friends.push(friend.screen_name);
            }
            callback(friends);
        },
        error: function() {
            displayMessage('Failed to get twitter friends');
        },
    });
}
var noun_twitter_friend = {
    _name: "twitter friend",
    friend_list: null,
    callback: function(friends) {
        noun_twitter_friend.friend_list = friends;
    },
    suggest: function(text, html) {
        if (noun_twitter_friend.friend_list == null) {
            get_twitter_friends(this.callback);
            return [];
        }
        if (text.length < 2)
        return [];
        var suggestions = [];
        for (i=0;i<noun_twitter_friend.friend_list.length;i++) {
            if (noun_twitter_friend.friend_list[i].match(text, "i"))
            suggestions.push(CmdUtils.makeSugg(noun_twitter_friend.friend_list[i]));
        }
        return suggestions.splice(0, 5);
    }
};
function getTwitterIds () {
    var passwordManager = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
    var logins = passwordManager.findLogins({}, "http://twitter.com", "", null);
    return logins;
}
var noun_twitter_id = {
    _name: "Twitter ID",
    id_list: null,
    suggest: function(text, html){
        if (text.length < 2) return [];
        if (noun_twitter_id.id_list == null){
            noun_twitter_id.id_list = getTwitterIds();
        }
        var suggs = [];
        for (var i = noun_twitter_id.id_list.length - 1; i >= 0; i--){
            if(noun_twitter_id.id_list[i].username.match(text, "i"))
                suggs.push(CmdUtils.makeSugg(noun_twitter_id.id_list[i].username));
        };
        return suggs.splice(0,5);
    }
}
function Twitter(usr, pwd) {
	this.usr = usr;
	this.pwd = pwd;
	this.updateUrl = "https://twitter.com/statuses/update.json";
	this.timelineUrl = "http://twitter.com/statuses/friends_timeline.json";
}
Twitter.prototype.send = function(msg) {
    var updateParams = {
        source: "ubiquity",
        status: msg
    };
    $j.ajax({
        type: "POST",
        url: this.updateUrl,
        data: updateParams,
        dataType: "json",
		username: this.usr,
		password: this.pwd,
        error: function(xhr, status, error) {
            displayMessage("Twitter error - status not updated because: " + xhr.statusText);
        },
        success: function() {
            if(auth){
                displayMessage("Twitter message posted as " + this.usr);
            }else{
                displayMessage("Twitter message posted");
            }
        }
    });
}
Twitter.prototype.friends_timeline = function(callback) {
    $j.ajax({
        url:this.timelineUrl,
        params:{count: 10},
        type:'GET',
        dataType:"json",
		username:this.usr,
		password:this.pwd,
        success: function(data) {
            data = data.slice(0,10);
            for (var entry in data) {
                data[entry]['text'] = data[entry]['text'].replace(/(https*:\/\/.*?)(\s|$)/gi, "<nobr><a href=\"$1\">$1</a></nobr>").replace(/@(\w+)/g, "<a href=\"http://twitter.com/$1\">@$1</a>").replace(/<a href/g, "<a style=\"color:#9999FF;\" href");
            }
            timeline = CmdUtils.renderTemplate(twitter_template, {
                entries: data
            });
            store.set(TWT_TIMELINE, timeline);
            store.set(TWT_TIMELINE_DATE, new Date());
			callback(store.get(TWT_TIMELINE, ''));
        }
    });
}
CmdUtils.CreateCommand({
    names: ["twtplus","twt","twitter","tweet"],
    icon: "http://assets1.twitter.com/images/favicon.ico",
    author: {
        name: "Damien Hou",
        email: "houyongr@gmail.com"
    },
    description: "Post message to Twitter.com with nifty features",
	help: "<p>Send a Twitter message with style.</p>"
		+'<p>Use "as" to post to different Twitter accounts (with auto-completion). (Accounts must be saved in Firefox account manager)</p>'
		+'<p>Use "to" to send a reply or dm to a friend (with friend username auto-completion)</p>'
		+'<p>Use "in" to specify whether to send a reply or a dm. Default is to send a reply if a friend is specified.</p>',
    homepage: "http://damienh.org/2009/03/02/twtplus-the-missing-twitter-command-for-ubiquity-and-firefox/",
    license: "MIT/MPL",
	arguments: [{role:'object', nountype:noun_arb_text, label:'message'},
				{role:'alias', nountype:noun_twitter_id, label:'user'},
				{role:'goal', nountype:noun_twitter_friend, label:'friend'},
				{role:'format', nountype:['reply','dm'], label:'reply or dm'}
				],
    getShortenedUrl: function(url){
        var shortUrl = url;
        $j.ajax({
            type: "GET",
            async: false,
            url: 'http://is.gd/api.php',
            data: {
                'longurl': url
            },
            error: function() {
                displayMessage("Failed to shorten URL");
            },
            success: function(shortened) {
                shortUrl = shortened;
            }
        });
        return shortUrl;
    },
    hasTimeline: function () {
        return store.has(TWT_TIMELINE);
    },
    getTimeline: function () {
        if (this.hasTimeline()) {
            return store.get(TWT_TIMELINE,'');
        }else{
            return '';
        }
    },
    setTimeline: function (timeline){
        store.set(TWT_TIMELINE, timeline);
    },
    timelineExpired: function () {
        var now = new Date();
        var update = store.has(TWT_TIMELINE_DATE) ? store.get(TWT_TIMELINE_DATE,'') : undefined;
        if (update != undefined) {
            delta = now - update;
            return delta > 120000;
        }else{
            return false;
        }
    },
    _update_timeline: function(p) {
        if (this.hasTimeline() && !this.timelineExpired()) {
            $j('#timeline',p).html(this.getTimeline());
        } else {
			var curLogin = getCurLogin();
			var twitter = new Twitter(curLogin.username, curLogin.password);
			twitter.friends_timeline(function(timeline){
				$j('#timeline',p).html(timeline);
			});
        }
    },
    preview: function(p, args) {
        p.innerHTML = "<div id='status'></div><div id='help'></div><div id='movies'><ul></ul></div><div id='books'><ul></ul></div><div id='music'><ul></ul></div><div style='clear:both'></div><div id='timeline'></div>";
        var results = this._processStatus(args);
        var status = results['status'];
        $j('#status', p).html('Preview: ' + results['status']);
        var rem = STATUS_MAXLEN - status.length;
        var help = "<p style=\"font-size:smaller;\">Remaining: " + rem + " chars. Type #url for the current URL. Click avatar to reply.</p>"
        $j('#help',p).html(help);
        this._update_timeline(p);
    },
    _processStatus: function(args) {
        var elements = {};
        //first, replace #url tag with actual current url
        var curUrl = CmdUtils.getDocument().URL;
        status = args.object.text.replace(/(^|\s)#url(\s|$)/, "$1" + curUrl + "$2");
        
        //shorten all urls
        var urls = status.match(/((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/g);
        if(urls){
            for (var i=0; i < urls.length; i++) {
                var shortened = this.getShortenedUrl(urls[i]);
                status = status.replace(urls[i], shortened);
            };
        }
        if(args.goal && args.goal.text){
	        if (args.format && args.format.text == 'dm') {
	            status = 'd '+args.goal.text+' '+status;
	        } else {
	            status = "@" + args["@"].text + " " + status;
			}
        }
        elements['status'] = status;
        return elements;
    },
    execute: function(args) {
        var statusText = this._processStatus(args)['status'];
        if (statusText.length < 1) {
            displayMessage("Forgot something to say?");
            return;
        }
        // detect the "as" phrase to select current twitter login user to post message
        var logins = getTwitterIds();
        if(args.as && args.as.text){
            var asLogin = args.as.text;
            for (var i = logins.length - 1; i >= 0; i--){
                if (logins[i].username == asLogin){
                    setCurLogin(logins[i]);
                    var name = getCurLogin().username;
                    break;
                }
            }
        }
        var curLogin = getCurLogin();
		var twitter = new Twitter(curLogin.username, curLogin.password);
		twitter.send(statusText);
    }
});