var retrieveListMessages = function(name, callback) {

   var DELAY = 100;
   var MAX_REQUESTS = 50;
   var INCLUDE_RECURSIONS = false;
   
   var listProxy = config.proxy + "synerge/listmembers.py?name=";

   var stage = 0;
   var listSize = 0;
   
   var main = function() {
      $.ajax({
         url: listProxy + name,
         async: true,
         dataType: "json",
         success: function(data) {
            debug("List size as returned by synerge.at: " + data.length);
            iterateUsers(data);
            stage = 1;
         },
         error: function(xhr, status, error) {
            debug(status);
            callback("error", status);
         }
      });
   
      var scheduler = setInterval(function() {
         if (stage < 2) {
            dequeue();
            callback("update", nodes);
         } else {
            clearInterval(scheduler);
            callback("finalize", nodes);
         }
         return;
      }, DELAY);
   
      return;
   }
   
   var queue = function(setup) {
      queue.requests.push(setup);
      return;
   }
   
   queue.requests = [];
   
   var dequeue = function() {
      if (queue.requests.length < 1) {
         return;
      }
      if (dequeue.requests < MAX_REQUESTS) {
         var request = queue.requests.shift();
         //request.async = false;
         //debug("Dequeuing request, " + queue.requests.length + " remaining");
         request.dataType = "json";
         // This is necessary for complete() to be called – jQuery bug?
         request.error = function(xhr, status, error) {
            callback("error", error);
            debug("An error occurred: ", status, error);
            debug("Twitter says the next search request should be made in " +
                  xhr.getResponseHeader("Retry-After") + " seconds");
         }
         request.success || (request.success = new Function);
         var complete = request.complete || new Function;
         request.complete = function(xhr, status) {
            complete();
            dequeue.requests -= 1;
         }
         $.ajax(request);
         dequeue.requests += 1;
         dequeue.totalRequests += 1;
      }
      return;
   }
   
   dequeue.requests = 0;
   dequeue.totalRequests = 0;
   
   var iterateUsers = function(users) {
      var query = "";   
      var queryCounter = resultCounter = 0;
   
      var getMessages = function(query) {
          queryCounter += 1;
          queue({
            url: config.proxy + "search.twitter.com/search.json?" + query,
            error: function(xhr, status, error) {
               debug("getMessages returned error (" + status + ") for " + query);
               callback("error", error);
            },
            success: function(data) {
               iterateMessages(data.results);
            },
            complete: function() {
               resultCounter += 1;
               if (queryCounter === resultCounter) {
                  stage = 2;
               }         
            }
         });
         return;
      }
   
      $.each(users, function(index, user) {
         if (!user) {
            debug("Something is wrong with a user: " + user); 
            return;
         }
         var node = Node.add(user);
         var part = encodeURIComponent("to:" + node.name);
         if (query.length < 1) {
            query = "rpp=100&q=" + part;
         } else {
            var term = "+OR+" + part;
            if (140 - query.length < term.length) {
               getMessages(query);
               query = "rpp=100&q=" + part;
            } else {
               query += term;
            }
         }
      });
   
      if (query.length > 0) {
         // One more call for getMessages() needed
         getMessages(query);
      }
      return;
   }
   
   var iterateMessages = function(messages) {
      $.each(messages, function(index, message) {
         var node1 = message.from_user && Node.get(message.from_user.toLowerCase());
         var node2 = message.to_user && Node.get(message.to_user.toLowerCase());
         if (node1 && node2) {
            node1.connectWith(node2);
         }
      });
      return;
   }
   
   return main();
}

