#!/usr/bin/env node
var dnode   = require('dnode'),
    path    = require('path'),
    config  = require('./config.js'),
    git_util   = require('./git_util.js'),
    Codesearch = require('./codesearch.js');

var REPO = process.argv[2] || '/home/nelhage/code/linux-2.6/';
var REF  = process.argv[3] || 'v3.0';
var args = process.argv.slice(4);

/*
 * Used to invoke callbacks on remote objects, where they may or may not provide
 * a method of the appropriate name, or may provide something that is not even a
 * function.
 *
 * An alternate approach would be to validate remote objects as soon as we get
 * them, but that seems more error-prone, especially during prototyping.
 */
function remote_call(obj, fn) {
  var args = Array.prototype.slice.call(arguments, 2);
  try {
    obj[fn].apply(obj, args);
  } catch (e) { }
}

function Client(parent, remote) {
  this.parent = parent;
  this.remote = remote;
}

Client.prototype.ready = function() {
  remote_call(this.remote, 'ready');
}

Client.prototype.search = function (re, cb) {
  var search = this.parent.codesearch.search(re);
  search.on('error', remote_call.bind(null, cb, 'error'));
  search.on('done',  remote_call.bind(null, cb, 'done'));
  search.on('match', remote_call.bind(null, cb, 'match'));
}

function Server(repo, ref, args) {
  var parent = this;
  this.codesearch = null
  this.clients = [];

  git_util.rev_parse(
    repo, ref,
    function (err, sha1) {
      if (err) throw err;
      console.log("Searching commit %s (%s)", ref, sha1);
      parent.codesearch = new Codesearch(repo, [sha1], {
                                           args: args
                                         });

      parent.codesearch.on('ready', function () {
                             Object.keys(parent.clients).forEach(
                               function (id) {
                                 parent.clients[id].ready();
                               });
                           });
    });

  this.Server = function (remote, conn) {
    parent.clients[conn.id] = new Client(parent, remote);
    conn.on('end', function() {
              delete parent.clients[conn.id];
            });
    this.try_search = function(re, cb) {
      if (parent.readyState !== 'ready') {
        remote_call(cb, 'not_ready');
        return;
      }
      parent.clients[conn.id].search(re, cb);
    }
    this.search = function(re, cb) {
      parent.clients[conn.id].search(re, cb);
    }
  }
}

var server = dnode(new Server(REPO, REF, args).Server);
server.listen(config.DNODE_PORT);

@@ -1027,24 +1027,271 @@
  (re, cb) %7B%0A
+  if (this.parent.codesearch.readyState !== 'ready') %7B%0A    this.parent.queue.push(%7B%0A                             client: this,%0A                             re: re,%0A                             cb: cb%0A                           %7D);%0A    return;%0A  %7D%0A
   var search
@@ -1608,16 +1608,37 @@
 ts = %5B%5D;
+%0A  this.queue   = %5B%5D;
 %0A%0A  git_
@@ -1982,24 +1982,288 @@
 nction () %7B%0A
+                             var q;%0A                             if (parent.queue.length) %7B%0A                               q = parent.queue.shift();%0A                               q.client.search.call(q.client, q.re, q.cb);%0A                             %7D else %7B%0A  
             
@@ -2316,16 +2316,18 @@
 orEach(%0A
+  
         
@@ -2394,24 +2394,26 @@
             
+  
 parent.clien
@@ -2424,24 +2424,26 @@
 d%5D.ready();%0A
+  
             
@@ -2461,24 +2461,55 @@
         %7D);%0A
+                             %7D%0A
             
@@ -2664,24 +2664,222 @@
 unction() %7B%0A
+              var client = parent.clients%5Bconn.id%5D;%0A              parent.queue = parent.queue.filter(%0A                function (q) %7B%0A                  return q.client !== client%0A                %7D);%0A
             

Make .search() queue results if the server isn't ready.