var lookup = require('dns').lookup,
    isIP = require('net').isIP,
    inherits = require('util').inherits,
    EventEmitter = require('events').EventEmitter;

var addon = require('../build/Release/sqlclient');

addon.Client.prototype.__proto__ = EventEmitter.prototype;

function clone(o) {
  var n = Object.create(Object.getPrototypeOf(o)),
      props = Object.getOwnPropertyNames(o),
      pName, p;
  for (p in props) {
    pName = props[p];
    Object.defineProperty(n, pName, Object.getOwnPropertyDescriptor(o, pName));  
  };
  return n;
}

function Client() {
  var self = this;
  this._closeOnEmpty = false;
  this._queries = [];
  this._curquery = undefined;
  this._client = new addon.Client();
  this._client.connected = false;
  this._client.on('connect', function() {
    self._client.connected = true;
    self.emit('connect');
  });
  this._client.on('error', function(err) {
    if (err.when === 'query' || err.when === 'result')
      self._curquery.emit('error', err);
    else
      self.emit('error', err);
  });
  this._client.on('close', function(had_err) {
    self._client.connected = false;
    self.emit('close', had_err);
  });
  this._client.on('queryAbort', function() {
    var q = self._curquery;
    self._curquery = undefined;
    process.nextTick(function() { q.emit('abort'); });
    self._processQueries();
  });
  this._client.on('result', function(res) {
    self._curquery.emit('result', res);
  });
  this._client.on('done', function() {
    var q = self._curquery;
    self._curquery = undefined;
    q.emit('end');
    self._processQueries();
  });
}
inherits(Client, EventEmitter);

Client.prototype.isConnected = function() {
  return this._client.connected;
};

Client.prototype.isMariaDB = function() {
  return this._client.isMariaDB();
};

Client.prototype._reset = function() {
  this._closeOnEmpty = false;
  this._queries = [];
  this._curquery = undefined;
};

Client.prototype.connect = function(cfg) {
  var self = this;
  if (!isIP(cfg.host)) {
    lookup(cfg.host, function(err, address, family) {
      if (err)
        return self.emit('error', err);
      cfg = clone(cfg);
      cfg.host = address;
      self._client.connect(cfg);
      self._reset();
    });
  } else {
    this._client.connect(cfg);
    this._reset();
  }
};

Client.prototype.close = function(immediate) {
  if (immediate || (this._curquery === undefined && !this._queries.length))
    this._client.end();
  else
    this._closeOnEmpty = true;
};

Client.prototype.query = function(query) {
  var self = this,
      queryObj = new Query(this),
      newLen = this._queries.push([query, queryObj]);
  queryObj._pairRef = this._queries[newLen - 1];
  this._processQueries();
  return queryObj;
};

Client.prototype.escape = function(str) {
  return this._client.escape(str);
};

Client.prototype._processQueries = function() {
  if (this._curquery === undefined) {
    if (this._queries.length) {
      var query = this._queries.shift();
      this._curquery = query[1];
      this._client.query(query[0]);
    } else if (this._closeOnEmpty)
      this.close(true);
  }
};

function Query(client) {
  this.client = client;
  this._pairRef = undefined;
  this._detached = false;
}
inherits(Query, EventEmitter);
Query.prototype.abort = function() {
  if (!this._detached) {
    var i;
    if (this === this.client.curquery) {
      this.client._client.abortQuery();
      this._detached = true;
    } else if ((i = this.client._queries.indexOf(this._pairRef)) > -1) {
      var self = this;
      this.client._queries.splice(i, 1);
      this._detached = true;
      process.nextTick(function() { self.emit('abort'); });
    }
    if (this._detached) {
      this._pairRef = undefined;
      this.client = undefined;
    }
  }
  return this._detached;
};

module.exports = Client;
@@ -838,16 +838,44 @@
 nect');%0A
+    self._processQueries();%0A
   %7D);%0A  
@@ -1015,24 +1015,85 @@
 r);%0A    else
+ %7B%0A      self._client.connected = false;%0A      self._reset();
 %0A      self.
@@ -1108,24 +1108,30 @@
 ror', err);%0A
+    %7D%0A
   %7D);%0A  this
@@ -1203,24 +1203,43 @@
 ed = false;%0A
+    self._reset();%0A
     self.emi
@@ -1736,16 +1736,210 @@
 tter);%0A%0A
+Client.prototype._reset = function() %7B%0A  this._closeOnEmpty = false;%0A  // TODO: do not empty queries if using an auto-reconnect algorithm%0A  this._queries = %5B%5D;%0A  this._curquery = undefined;%0A%7D;%0A%0A
 Client.p
@@ -2096,133 +2096,8 @@
 %7D;%0A%0A
-Client.prototype._reset = function() %7B%0A  this._closeOnEmpty = false;%0A  this._queries = %5B%5D;%0A  this._curquery = undefined;%0A%7D;%0A%0A
 Clie
@@ -2371,37 +2371,16 @@
 t(cfg);%0A
-      self._reset();%0A
     %7D);%0A
@@ -2383,26 +2383,24 @@
 %7D);%0A  %7D else
- %7B
 %0A    this._c
@@ -2423,31 +2423,8 @@
 g);%0A
-    this._reset();%0A  %7D%0A
 %7D;%0A%0A
@@ -3023,16 +3023,38 @@
 ndefined
+ && this.isConnected()
 ) %7B%0A    
@@ -3959,12 +3959,13 @@
 ts = Client;
+%0A

Allow already enqueued queries to be executed automatically upon connection