text: /* global exports: true */
  var errors = require( '../errors' );
  
  /**
   *
   * @module        sendRequest
   *
   * @description   This function provides the lowest-level interface to the XHR functionality that
   *                the Bridge Client is operating on top of. This function is responsible only for
   *                issuing a request and returning a Q promise and hooking up the resolve() and
   *                reject() methods to the results of the XHR request.
   *                This function can be overridden to use some other service than XmlHttpRequests
   *                by the end-developer. If you plan to do this, we advice that you make a plugin
   *                for the Bridge Client to formalize your specialized behaviour. Ensure that the
   *                overriding function adhered to the same signature and returns a Q promise.
   *
   * @param         {Deferred} deferred   A Q deferred object that the end-developer must use to
   *                                      either resolve or reject in response to the request either
   *                                      failing or completing successfully.
   *
   * @param         {String} method       The HTTP verb/action to use for the request.
   *
   * @param         {String} url          The exact URL of the resource to query.
   *
   * @param         {Object} data         The data object to send with the request. This can be used
   *                                      to describe query arguments such as filters and ordering,
   *                                      or to contain data to be stored in the Bridge database.
   *
   * @returns       {Promise}             A q.js promise object.
   *
   */
  module.exports = function sendRequest( deferred, method, url, data ) {
  
    'use strict';
  
    var xhr = new XMLHttpRequest();
  
    xhr.open( method.toUpperCase(), url, true );
    xhr.setRequestHeader( 'Accept', 'application/json' );
    xhr.setRequestHeader( 'Bridge', JSON.stringify( data ) );
  
    xhr.onreadystatechange = function () {
      if ( xhr.readyState === 4 ) {
        try {
  
          // Attempt to parse the response as JSON.
          var data = JSON.parse( xhr.responseText );
  
          // If the content property is missing from the response, the response is malformed. Reject
          // the request with a new error object indicating that the response is malformed.
          if ( !data.content ) {
            deferred.reject( new errors.BridgeError( errors.MALFORMED_RESPONSE ) );
          }
  
          // If an error status is reported, reject the request with the response's error object.
          if ( xhr.status >= 400 ) {
            deferred.reject( data.content );
          }
  
          // Otherwise, resolve the request with the response object.
          deferred.resolve( data.content );
  
        }
        catch ( e ) {
  
          // If the response can't be parsed as JSON, reject the request with a new error object that
          // describes the response as malformed.
          deferred.reject( new errors.BridgeError( errors.MALFORMED_RESPONSE ) );
  
        }
      }
    };
  
    xhr.onerror = function () {
  
      // If the request failed due to a network error, reject the request with a new error object that
      // describes that the failure was due to a network error.
      deferred.reject( new errors.BridgeError( errors.NETWORK_ERROR ) );
  
    };
  
    xhr.ontimeout = function () {
  
      // If the request timed out, reject the request with a new error object that describes that the
      // failure was due to a timeout.
      deferred.reject( new errors.BridgeError( errors.REQUEST_TIMEOUT ) );
  
    };
  
    xhr.send();
  
    return deferred.promise;
  
  };
  