// Parse resource record:
//  - variable length name
//  - 16-bit RR type
//  - 16-bit RR class
//  - 32-bit TTL
//  - 16-bit resource data length in bytes
//  - variable length resource data
function unpackResourceRecord(buf, offset) {
  var bytes = 0;

  //  - variable length name
  var nbname = NBName.fromBuffer(buf, offset + bytes);
  if (nbname.error) {
    return {error: nbname.error};
  }

  bytes += nbname.bytesRead;

  var record = {};
  record.nbname = nbname;

  //  - 16-bit RR type
  var t = buf.readUInt16BE(offset + bytes);
  bytes += 2;

  record.type = con.RR_TYPE_TO_STRING[t];
  if (record.type === undefined) {
    return {
      error: new Error('Illegal resource record type [' + t + '] for name [' +
                       nbname + ']')
    };
  }
  var rdataParser = RR_TYPE_TO_PARSER[record.type];

  //  - 16-bit RR class
  var clazz = buf.readUInt16BE(offset + bytes);
  bytes += 2;

  if (clazz !== con.CLASS_IN) {
    return {
      error: new Error('Unexpected resource record class [' + clazz +
                       '] for name [' + record.nbname + ']; expected class [' +
                       con.CLASS_IN + '].')
    };
  }

  //  - 32-bit TTL
  record.ttl = buf.readUInt32BE(offset + bytes);
  bytes += 4;

  //  - 16-bit resource data length in bytes
  var dataLen = buf.readUInt16BE(offset + bytes);
  bytes += 2;

  //  - variable length resource data
  var res = rdataParser(buf, offset + bytes, dataLen, record);
  if (res.error) {
    return {error: res.error};
  }

  bytes += res.bytesRead;

  return {bytesRead: bytes, record: record};
}
// Parse question section
//  - variable length compressed question name
//  - 16-bit question type
//  - 16-bit question class
function unpackQuestion(buf, offset) {
  var bytes = 0;
  var question = {};

  //  - variable length compressed question name
  var nbname = NBName.fromBuffer(buf, offset + bytes);
  if (nbname.error) {
    return {error: nbname.error};
  }

  question.nbname = nbname;
  bytes += nbname.bytesRead;

  // Ensure we have enough space left before proceeding to avoid throwing
  if (offset + bytes + 4 > buf.length) {
    return {
      error: new Error('Question section is too large to fit in remaining ' +
                       'packet bytes.')
    };
  }

  //  - 16-bit question type
  var t = buf.readUInt16BE(offset + bytes);
  bytes += 2;

  question.type = con.QUESTION_TYPE_TO_STRING[t];
  if (question.type === undefined) {
    return {
      error: new Error('Unexpected question type [' + t + '] for name [' +
                       question.nbname + '];  should be either [nb] or ' +
                       '[nbstat]')
    };
  }

  //  - 16-bit question class
  var clazz = buf.readUInt16BE(offset + bytes);
  bytes += 2;

  if (clazz !== con.CLASS_IN) {
    return {
      error: new Error('Unexpected question class [' + clazz +
                       '] for name [' + question.nbname + '];  should be [' +
                       CLASS_IN + ']')
    };
  }

  return {bytesRead: bytes, record: question};
}
function nsRDataParser(buf, offset, length, record) {
  var bytes = 0;

  var nbname = NBName.fromBuffer(buf, offset + bytes);
  if (nbname.error) {
    return {error: nbname.error};
  } else if (length !== nbname.bytesRead) {
    return {
      error: new Expect('Unexpected NS record name length for record [' +
                        record.nbname + '].')
    };
  }

  bytes += nbname.bytesRead;

  record.ns = {
    nbname: nbname,
  };

  return {bytesRead: bytes};
}