'use strict';
/**
 * This object contains all the handlers to use for this providers
 */
var googleapis = require('googleapis');
var rarity = require('rarity');
var OAuth2Client = googleapis.OAuth2Client;

var config = require('../config/configuration.js');
var retrieveContacts = require('./helpers/retrieve.js');
var uploadContact = require('./helpers/upload.js');

var redirectToService = function(callbackUrl, cb) {
  googleapis.execute(function(err) {
    if(err) {
      return cb(err);
    }

    var oauth2Client = new OAuth2Client(config.googleId, config.googleSecret, callbackUrl);

    // generate consent page url for Google Contacts access, even when user is not connected (offline)
    var redirectUrl = oauth2Client.generateAuthUrl({
      access_type: 'offline',
      scope: 'https://www.google.com/m8/feeds https://www.googleapis.com/auth/userinfo.email',
      approval_prompt: 'force', // Force resending a refresh_token
    });

    cb(null, redirectUrl, {redirectUrl: redirectUrl, callbackUrl: callbackUrl});
  });
};

var retrieveTokens = function(reqParams, storedParams, cb) {
  googleapis
  .discover('oauth2', 'v2')
  .execute(function(err, client) {
    var oauth2Client = new OAuth2Client(config.googleId, config.googleSecret, storedParams.callbackUrl);

    // request tokens set
    oauth2Client.getToken(reqParams.code, function(err, tokens) {
      if(err) {
        return cb(new Error(err));
      }

      // Set tokens to the client
      // Not really useful in our case.
      oauth2Client.credentials = tokens;

      client.oauth2.userinfo.get().withAuthClient(oauth2Client).execute(function(err, data){
        if(err) {
          return cb(err);
        }
        
        cb(null, data.email, tokens);
      });
    });
  });
};

var updateAccount = function(serviceData, cursor, queues, cb) {
  // Retrieve all contacts since last call
  if(!cursor) {
    cursor = new Date(1970);
  }
  var newCursor = new Date();

  retrieveContacts(serviceData.refresh_token, cursor, function(err, contacts) {
    if(contacts) {
      contacts.forEach(function(contact) {
        if(contact.deleted) {
          queues.deletion.push(contact);
        }
        else {
          queues.addition.push(contact);
        }
      });
    }

    cb(err, newCursor);
  });
};

var additionQueueWorker = function(job, cb) {
  uploadContact(job.task, job.anyfetchClient, job.serviceData.refresh_token, cb);
};

var deletionQueueWorker = function(job, cb) {
  job.anyfetchClient.deleteDocument(job.task.url, rarity.slice(1, cb));
};

module.exports = {
  connectFunctions: {
    redirectToService: redirectToService,
    retrieveTokens: retrieveTokens
  },
  updateAccount: updateAccount,
  workers: {
    addition: additionQueueWorker,
    deletion: deletionQueueWorker
  },

  config: config
};

@@ -150,24 +150,54 @@
 ('rarity');%0A
+var async = require('async');%0A
 var OAuth2Cl
@@ -1117,32 +1117,75 @@
 edParams, cb) %7B%0A
+  async.waterfall(%5B%0A    function(cb) %7B%0A    
   googleapis%0A  .
@@ -1180,19 +1180,16 @@
 ogleapis
-%0A  
 .discove
@@ -1205,19 +1205,16 @@
 ', 'v2')
-%0A  
 .execute
@@ -1206,32 +1206,48 @@
 , 'v2').execute(
+cb);%0A    %7D,%0A    
 function(err, cl
@@ -1243,23 +1243,24 @@
 ion(
-err, 
 client
+, cb
 ) %7B%0A
+  
     
@@ -1364,35 +1364,10 @@
 l);%0A
-%0A
   
-  // request tokens set%0A
     
@@ -1408,87 +1408,66 @@
 de, 
-function(err, tokens) %7B%0A      if(err) %7B%0A        return cb(new Error(err
+rarity.carryAndSlice(%5Boauth2Client, client%5D, 4, cb
 ));%0A    
   %7D%0A
@@ -1466,86 +1466,59 @@
     
-  %7D%0A
+%7D,
 %0A    
-  // Set tokens to the client%0A      // Not really useful in our case.
+function(oauth2Client, client, tokens, cb) %7B
 %0A   
@@ -1555,17 +1555,16 @@
 tokens;%0A
-%0A
       cl
@@ -1631,94 +1631,88 @@
 ute(
-function(err, data)%7B%0A        if(err) %7B%0A          return cb(err);%0A        %7D%0A        %0A  
+rarity.carryAndSlice(%5Btokens%5D, 3, cb));%0A    %7D,%0A    function(tokens, data, cb) %7B%0A
     
@@ -1751,25 +1751,17 @@
     
-  %7D);%0A    %7D);%0A  %7D
+%7D%0A  %5D, cb
 );%0A%7D

Add a waterfall