/*!
 * node-gcm
 * Copyright(c) 2013 Marcus Farkas <toothlessgear@finitebox.com>
 * MIT Licensed
 */
var Constants = require('./constants');
var req = require('request');
var debug = require('debug')('node-gcm');

function Sender(key , options) {
    if (!(this instanceof Sender)) {
        return new Sender(key, options);
    }

    this.key = key;
    this.options = options;
}

Sender.prototype.sendNoRetry = function(message, registrationIds, callback) {
    if(!callback) {
        callback = function() {};
    }

    var body = {},
        requestBody,
        post_options,
        post_req,
        timeout;

    body[Constants.JSON_REGISTRATION_IDS] = registrationIds;

    if (message.delayWhileIdle !== undefined) {
        body[Constants.PARAM_DELAY_WHILE_IDLE] = message.delayWhileIdle;
    }
    if (message.collapseKey !== undefined) {
        body[Constants.PARAM_COLLAPSE_KEY] = message.collapseKey;
    }
    if (message.timeToLive !== undefined) {
        body[Constants.PARAM_TIME_TO_LIVE] = message.timeToLive;
    }
    if (message.dryRun !== undefined) {
        body[Constants.PARAM_DRY_RUN] = message.dryRun;
    }
    if (Object.keys(message.data)) {
        body[Constants.PARAM_PAYLOAD_KEY] = message.data;
    }

    requestBody = JSON.stringify(body);

    post_options = {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Content-length': Buffer.byteLength(requestBody, 'utf8'),
            'Authorization': 'key=' + this.key
        },
        uri: Constants.GCM_SEND_URI,
        body: requestBody
    };

    if (this.options && this.options.proxy) {
        post_options.proxy = this.options.proxy;
    }

    if (this.options && this.options.maxSockets) {
        post_options.maxSockets = this.options.maxSockets;
    }

    timeout = Constants.SOCKET_TIMEOUT;

    if (this.options && this.options.timeout) {
        timeout =  this.options.timeout;
    }

    post_options.timeout = timeout;

    post_req = req(post_options, function (err, res, resBody) {

        if (err) {
            return callback(err, null);

        }
        if (!res) {
            return callback('response is null', null);

        }
        if (res.statusCode >= 500) {
            debug('GCM service is unavailable (500)');
            return callback(res.statusCode, null);
        } else if (res.statusCode === 401) {
            debug('Unauthorized (401). Check that your API token is correct.');
            return callback(res.statusCode, null);
        } else if (res.statusCode !== 200) {
            debug('Invalid request (' + res.statusCode + '): ' + resBody);
            return callback(res.statusCode, null);
        }

        try {
            callback(null, JSON.parse(resBody));
        } catch (e) {
            debug("Error handling GCM response " + e);
            callback("error", null);
        }
    });
};

Sender.prototype.send = function(message, registrationIds, retries, backoff, callback) {
    if(typeof backoff == "undefined" || typeof backoff == "function") {
        callback = backoff;
        backoff = Constants.BACKOFF_INITIAL_DELAY;
    }
    if(typeof retries == "undefined" || typeof retries == "function") {
        callback = retries;
        retries = 5;
    }
    if(!callback) {
        callback = function() {};
    }
    
    if (!registrationIds.length) {
        debug('No RegistrationIds given!');
        callback('No RegistrationIds given!', null);
        return;
    }

    if(retries == 0) {
        return this.sendNoRetry(message, registrationIds, callback);
    }
    if (backoff > Constants.MAX_BACKOFF_DELAY) {
        backoff = Constants.MAX_BACKOFF_DELAY;
    }

    var self = this;

    this.sendNoRetry(message, registrationIds, function(err, result) {
        // if we err'd resend them all
        if (err) {
            return self.send(message, registrationIds, retries - 1, backoff * 2, callback);
        }

        // check for bad ids
        var unsentRegIds = [], regIdPositionMap = [];
        for (var i = 0; i < registrationIds.length; i++) {
            if (result.results[i].error === 'Unavailable') {
                regIdPositionMap.push(i);
                unsentRegIds.push(registrationIds[i]);
            }
        }

        if (!unsentRegIds.length) {
            return callback(err, result);
        }

        debug("Results received but not all successful", result);

        setTimeout(function () {
            debug("Retrying unsent registration ids");
            self.send(message, unsentRegIds, retries - 1, backoff * 2, function(err, retriedResult) {
                //If the recursive call err'd completely, our current result is the best available
                if(err) {
                    return callback(null, result);
                }

                //Map retried results onto their previous positions in the full array
                var retriedResults = retriedResult.results;
                for(var i = 0; i < result.results.length; i++) {
                    var oldIndex = regIdPositionMap[i];
                    result.results[oldIndex] = retriedResults[i];
                }
                callback(null, result);
            });
        }, backoff);
    });
};

module.exports = Sender;
@@ -2967,24 +2967,15 @@
 ds, 
-retries, backoff
+options
 , ca
@@ -2992,102 +2992,106 @@
     
-if(typeof backoff == %22undefined%22 %7C%7C typeof backoff == %22function%22) %7B%0A        callback = backoff
+var backoff, retries;%0A%0A    if(typeof options == %22object%22) %7B%0A        retries = options.retries %7C%7C 5
 ;%0A  
@@ -3097,32 +3097,51 @@
        backoff =
+ options.backoff %7C%7C
  Constants.BACKO
@@ -3164,24 +3164,29 @@
 ;%0A    %7D%0A    
+else 
 if(typeof re
@@ -3187,65 +3187,104 @@
 eof 
-retrie
+option
 s == %22
+f
 un
-defined%22 %7C%7C typeof retries == %22function%22) %7B
+ction%22) %7B%0A        retries = 5;%0A        backoff = Constants.BACKOFF_INITIAL_DELAY;
 %0A   
@@ -3303,44 +3303,149 @@
 k = 
-retrie
+option
 s;%0A    
-    retries = 5
+%7D%0A    else if(typeof options == %22number%22) %7B%0A        retries = options;%0A        backoff = Constants.BACKOFF_INITIAL_DELAY
 ;%0A    %7D%0A
     
@@ -3436,24 +3436,25 @@
 ELAY;%0A    %7D%0A
+%0A
     if(!call
@@ -3501,20 +3501,16 @@
 ;%0A    %7D%0A
-    
 %0A    if 

Change interface of function to take `options` instead of `retries` and `backoff` This requries changing the defaulting of arguments