text: /*!
   * node-gcm
   * Copyright(c) 2013 Marcus Farkas <toothlessgear@finitebox.com>
   * MIT Licensed
   */
  var Constants = require('./constants');
  var Result = require('./result');
  
  var request = require('request');
  var timer = require('timers');
  
  
  function Sender(config, key, endpoint) {
      this.key = key;
      this.endpoint = endpoint
      this.proxy = config.httpProxy;
      this.timeout = config.timeout
  }
  
  var sendNoRetryMethod = Sender.prototype.sendNoRetry = function (message, registrationIds, callback) {
      var body = {},
          result = new Result(),
          requestBody,
          post_options,
          post_req;
  
      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.hasData) {
          body[Constants.PARAM_PAYLOAD_KEY] = message.data;
      }
  
      post_options = {
          url: this.endpoint || Constants.GCM_SEND_ENDPOINT,
          json: body,
          encoding: 'utf-8',
          headers: {
              'Authorization': 'key=' + this.key
          },
          timeout: this.timeout,
      };
  
      if (this.proxy) {
          post_options['proxy'] = this.proxy;
      }
  
      request.post(post_options, function (err, resp, body) {
          if (err) {
              console.log("Exception during GCM request: " + err);
              callback("request error", null);
          } else if (resp.statusCode === 503) {
              console.log('GCM service is unavailable');
              return callback(resp.statusCode, null);
          } else if(resp.statusCode == 401){
              console.log('Unauthorized');
              return callback(resp.statusCode, null);
          } else if (resp.statusCode !== 200) {
              console.log('Invalid request: ' + resp.statusCode);
              return callback(resp.statusCode, null);
          } else if (typeof body != 'object') {
              console.log("Error parsing GCM response");
              callback("error", null);
          } else {
              callback(null, body);
          }
      });
  };
  
  Sender.prototype.send = function (message, registrationId, retries, callback) {
  
      var attempt = 1,
          backoff = Constants.BACKOFF_INITIAL_DELAY;
  
      if (registrationId.length === 1) {
  
          this.sendNoRetry(message, registrationId, function lambda(err, result) {
  
              if (result === undefined) {
                  if (attempt < retries) {
                      var sleepTime = backoff * 2 * attempt;
                      if (sleepTime > Constants.MAX_BACKOFF_DELAY) {
                          sleepTime = Constants.MAX_BACKOFF_DELAY;
                      }
                      timer.setTimeout(function () {
                          sendNoRetryMethod(message, registrationId, lambda);
                      }, sleepTime);
                  } else {
                      console.log('Could not send message after ' + retries + ' attempts');
                      callback(null, result);
                  }
                  attempt += 1;
              } else callback(null, result);
          });
      } else if (registrationId.length > 1) {
          this.sendNoRetry(message, registrationId, function lambda(err, result) {
  
              if (attempt < retries) {
                  var sleepTime = backoff * 2 * attempt,
                      unsentRegIds = [],
                      i;
                  if (sleepTime > Constants.MAX_BACKOFF_DELAY) {
                      sleepTime = Constants.MAX_BACKOFF_DELAY;
                  }
  
                  if (result) {
                      for (i = 0; i < registrationId.length; i += 1) {
                          if (result.results[i].error === 'Unavailable') {
                              unsentRegIds.push(registrationId[i]);
                          }
                      }
                  }
  
                  registrationId = unsentRegIds;
                  if (registrationId.length !== 0) {
                      timer.setTimeout(function () {
                          sendNoRetryMethod(message, registrationId, lambda);
                      }, sleepTime);
                      attempt += 1;
                  } else callback(null, result);
  
              } else {
                  console.log('Could not send message to all devices after ' + retries + ' attempts');
                  callback(null, result);
              }
          });
      } else {
          console.log('No RegistrationIds given!');
      }
  };
  
  module.exports = Sender;
  