// ==UserScript==
// @name           Gmail
// @namespace      MikeStay
// @description    Javascript Gmail API
// @include        file://*
// ==/UserScript==

function Gmail(){}
var gp=Gmail.prototype;

gp.gr=GM_xmlhttpRequest;
gp.url={
    base:'https://mail.google.com/mail/h/_/?',
    login:'https://www.google.com/accounts/ServiceLoginBoxAuth',
    logout:'https://mail.google.com/mail/?logout'
};

gp.action={
    getAuthToken:'&v=b&cs=b',
    message:'&v=b&s=d&fv=b&cpt=c&pv=tl&cs=c&at=', //+auth token
    postNewMessage:'&redir=%3Fs%3Dd',
    send:'&nvp_bu_send=Send',
    draft:'&nvp_bu_sd=Save%20Draft',
    discard:'&nvp_bu_d=Discard',
    search:'&s=q&nvp_site_mail=Search%20Mail&q=', //+escaped search query
    token:'&s=d&at=', //+authToken
    label:'&bact=&nvp_tbu_go=Go&redir=%3Fs%3Dd&t=', // + threadId
    removeLabel:'&tact=rc_', // + label
    addLabel:'&tact=ac_', // + label
};

gp.regExp={
    loginError:/Username and password do not match|Required field cannot be left blank/,
    getFirstSearchHit:/(v=b\&draft=[^"]*)/,                     // i.e. find the first link referring to a draft conversation
    getAllSearchHits:/(v=b\&draft=[^"]*)">((\r|\n|.)*?)<\/a>/g, // i.e. find each link referring to a draft conversation
    cleanHits:/<.*?>|\r|\n|"/g,                                 // i.e. strip out tags, newlines, quotes
    getDraftBody:/textarea name=body(\r|\n|.)*?>((\r|\n|.)*?)</m,
    getAuthToken:/form action="[^"]*at=([^\&"]*)/,
    getThreadId:/form action="[^"]*draft=([^\&"]*)/,
};

gp.login=function (email,password,onsuccess,onfail)
{
    var _onsuccess=onsuccess || function(){};
    var _onfail=onfail || function(){};
    this.gr({
        method:'GET',
        url:this.url.login+"?Email="+email+"&Passwd="+password,
        'onload':(function(self){return function(r){if (r.responseText.match(self.regExp.loginError)) _onfail(); else _onsuccess();}})(this)
    });
};

gp.logout=function()
{
    this.gr({
        method:'GET',
        url:this.url.logout
    });
};

// compose a new draft, extract thread id
gp.getAuthToken=function(callback /* (authToken) */ )
{
    this.gr({
        method:'GET',
        url:this.url.base+this.action.getAuthToken,
        onload:(function(self){return function(r){
            r.responseText.match(self.regExp.getAuthToken);
            callback(RegExp.$1);
        }})(this)
    });    
};

gp.composeDraft=function(authToken,
                         data /* object with members named to, subject, cc, body; no attachments */,
                         callback /* (threadId) */)
{
    var escapedData;
    for (var i in data) escapedData+='&'+escape(i)+'='+escape(data[i]);

    this.gr({
        method:'POST',
        url:this.url.base+this.action.message+authToken,
        headers:{'Content-type':'application/x-www-form-urlencoded'},
        data:this.action.postNewMessage+this.action.draft+escapedData,
        onload:(function(self){return function(r){
        	r.responseText.match(self.regExp.getThreadId);
        	callback(RegExp.$1);
        }})(this)

    });
};

gp.updateDraft=function(authToken,
						threadId,
                        data /* object with members named to, subject, cc, body; no attachments */,
                        callback)
{
    var escapedData;
    for (var i in data) escapedData+='&'+escape(i)+'='+escape(data[i]);

    this.gr({
        method:'POST',
        url:this.url.base+this.action.message+authToken+"&draft="+threadId,
        headers:{'Content-type':'application/x-www-form-urlencoded'},
        data:this.action.postNewMessage+this.action.draft+escapedData,
        onload:callback
    });
};


gp.getDraftBySubject=function(subject,onsuccess /* (body) */, onfail)
{
    this.gr({
        method:'GET',
        url:this.url.base+this.action.search+escape('subject:"'+subject+'" in:drafts'),
        onload:(function(self){return function(r){
            if (r.responseText.match(self.regExp.getFirstSearchHit)){
                self.gr({
                    method:'GET',
                    url:self.url.base+RegExp.$1,
                    onload:(function(self){return function(r){
                        r.responseText.match(self.regExp.getDraftBody);
                        onsuccess(RegExp.$2);
                    }})(self)                    
                });
            } else {
                onfail();
            }
        }})(this)
    });
};

// search for a word in your notes
// returns up to 20 hits
gp.getTrackbacks=function(word, startIndex, callback /* (results) */)
{
    this.gr({
        method:'GET',
        url:this.url.base+this.action.search+escape("in:drafts "+word),
        onload:(function(self){return function(r){
            var searchHits=r.responseText.match(self.regExp.getAllSearchHits);
            if (searchHits){
                var results={};
                for (var i in searchHits){
                    var j=searchHits[i].replace(self.regExp.cleanHits,"");
                    var k=j.split(/>/);
                    results[k[0]]=k[1];
                }
                callback(results);
            } else {
                callback({});
            }
        }})(this)
    });
}

gp.addLabel=function(authToken, label, threadIds, callback)
{
	var temp={
		method:'POST',
		url:this.url.base+this.action.token+authToken,
		headers:{'Content-type':'application/x-www-form-urlencoded'},
		data:this.action.label+threadIds.join('&t=')+this.action.addLabel+label,
		onload:function(r){
			var a=document.createElement('textarea');
			a.rows=20; a.cols=100; a.value=r.responseText;
			document.body.appendChild(a);
		}
	};
	this.gr(temp);
}

////////////////////////////
// MAIN TESTING
////////////////////////////

g=new Gmail();

g.login('metaweta',prompt("password?"),
    function(){
        g.getAuthToken(
            function(token){
                alert("AuthToken:"+token);
                g.composeDraft(token,{
                        to:'mikestay@gmail.com',
                        subject:'new draft test',
                        body:'test!\ntest'
                    },
                    (function(token){return function(tid){
                    	alert(tid);
                        g.updateDraft(token, tid, {
                        	to:'stay@google.com',
                        	subject:'update draft',
                        	body:'It works!'
                    	},function(){alert('?')});
                    }})(token)
                );
            }
        );
    },
    function(){
        alert("Login Error");
    }
);







