// Generated by CoffeeScript 2.5.1
(function() {
  var SocksClient, _, cleanParsingErrors, net, punycode, util;

  _ = require('underscore');

  net = require('net');

  SocksClient = require('socks').SocksClient;

  punycode = require('punycode');

  util = require('util');

  this.SERVERS = require('./servers.json');

  cleanParsingErrors = (string) => {
    return string.replace(/^[:\s]+/, '').replace(/^https?[:\/]+/, '') || string;
  };

  this.lookup = (addr, options, done) => {
    var _lookup, parts, proxy, server, sockOpts, socket, timeout, tld;
    if (typeof done === 'undefined' && typeof options === 'function') {
      done = options;
      options = {};
      if (addr === '__proto__') {
        done(new Error('lookup: __proto__ is not allowed to lookup'));
        return;
      }
    }
    _.defaults(options, {
      follow: 2,
      timeout: 60000 // 60 seconds in ms
    });
    done = _.once(done);
    server = options.server;
    proxy = options.proxy;
    timeout = options.timeout;
    if (!server) {
      switch (true) {
        case _.contains(addr, '@'):
          done(new Error('lookup: email addresses not supported'));
          return;
        case net.isIP(addr) !== 0:
          server = this.SERVERS['_']['ip'];
          break;
        default:
          tld = punycode.toASCII(addr);
          while (true) {
            server = this.SERVERS[tld];
            if (!tld || server) {
              break;
            }
            tld = tld.replace(/^.+?(\.|$)/, '');
          }
      }
    }
    if (!server) {
      done(new Error('lookup: no whois server is known for this kind of object'));
      return;
    }
    if (typeof server === 'string') {
      parts = server.split(':');
      server = {
        host: parts[0],
        port: parts[1]
      };
    }
    if (typeof proxy === 'string') {
      parts = proxy.split(':');
      proxy = {
        ipaddress: parts[0],
        port: parseInt(parts[1])
      };
    }
    _.defaults(server, {
      port: 43,
      query: "$addr\r\n"
    });
    if (proxy) {
      _.defaults(proxy, {
        type: 5
      });
    }
    _lookup = (socket, done) => {
      var data, idn;
      idn = addr;
      if (server.punycode !== false && options.punycode !== false) {
        idn = punycode.toASCII(addr);
      }
      if (options.encoding) {
        socket.setEncoding(options.encoding);
      }
      socket.write(server.query.replace('$addr', idn));
      data = '';
      socket.on('data', (chunk) => {
        return data += chunk;
      });
      socket.on('timeout', () => {
        socket.destroy();
        return done(new Error('lookup: timeout'));
      });
      socket.on('error', (err) => {
        return done(err);
      });
      return socket.on('close', (err) => {
        var match;
        if (options.follow > 0) {
          match = data.replace(/\r/gm, '').match(/(ReferralServer|Registrar Whois|Whois Server|WHOIS Server|Registrar WHOIS Server|refer):[^\S\n]*((?:r?whois|https?):\/\/)?([0-9A-Za-z\.\-_]*)/);
          if ((match != null) && match[3] !== server.host) {
            options = _.extend({}, options, {
              follow: options.follow - 1,
              server: match[3].trim()
            });
            options.server = cleanParsingErrors(options.server);
            this.lookup(addr, options, (err, parts) => {
              if (err != null) {
                return done(err);
              }
              if (options.verbose) {
                return done(null, [
                  {
                    server: ('object' === typeof server) ? server.host.trim() : server.trim(),
                    data: data
                  }
                ].concat(parts));
              } else {
                return done(null, parts);
              }
            });
            return;
          }
        }
        if (options.verbose) {
          return done(null, [
            {
              server: ('object' === typeof server) ? server.host.trim() : server.trim(),
              data: data
            }
          ]);
        } else {
          return done(null, data);
        }
      });
    };
    if (!Number.isInteger(server.port)) {
      server.port = 43;
    }
    if (proxy) {
      return SocksClient.createConnection({
        proxy: proxy,
        destination: {
          host: server.host,
          port: server.port
        },
        command: 'connect',
        timeout: timeout
      }, (err, info) => {
        var socket;
        if (err != null) {
          return done(err);
        }
        ({socket} = info);
        if (timeout) {
          socket.setTimeout(timeout);
        }
        _lookup(socket, done);
        return socket.resume();
      });
    } else {
      sockOpts = {
        host: server.host,
        port: server.port
      };
      if (options.bind) {
        sockOpts.localAddress = options.bind;
      }
      socket = net.connect(sockOpts);
      if (timeout) {
        socket.setTimeout(timeout);
      }
      return _lookup(socket, done);
    }
  };

}).call(this);
