// Generated by CoffeeScript 1.7.1
var ReadableTrackingBuffer, convertLEBytesToString;

convertLEBytesToString = require('./bigint').convertLEBytesToString;


/*
  A Buffer-like class that tracks position.

  As values are read, the position advances by the size of the read data.
  When reading, if the read would pass the end of the buffer, an error object is thrown.
 */

ReadableTrackingBuffer = (function() {
  function ReadableTrackingBuffer(buffer, encoding) {
    this.buffer = buffer;
    this.encoding = encoding;
    if (!buffer) {
      this.buffer = new Buffer(0);
      this.encoding = void 0;
    }
    this.encoding || (this.encoding = 'utf8');
    this.position = 0;
  }

  ReadableTrackingBuffer.prototype.add = function(buffer) {
    this.buffer = Buffer.concat([this.buffer.slice(this.position), buffer]);
    return this.position = 0;
  };

  ReadableTrackingBuffer.prototype.assertEnoughLeftFor = function(lengthRequired) {
    var available, e;
    this.previousPosition = this.position;
    available = this.buffer.length - this.position;
    if (available < lengthRequired) {
      e = new Error("required : " + lengthRequired + ", available : " + available);
      e.code = 'oob';
      throw e;
    }
  };

  ReadableTrackingBuffer.prototype.empty = function() {
    return this.position === this.buffer.length;
  };

  ReadableTrackingBuffer.prototype.rollback = function() {
    return this.position = this.previousPosition;
  };

  ReadableTrackingBuffer.prototype.readUInt8 = function() {
    var length, value;
    length = 1;
    this.assertEnoughLeftFor(length);
    this.position += length;
    return value = this.buffer.readUInt8(this.position - length);
  };

  ReadableTrackingBuffer.prototype.readUInt16LE = function() {
    var length;
    length = 2;
    this.assertEnoughLeftFor(length);
    this.position += length;
    return this.buffer.readUInt16LE(this.position - length);
  };

  ReadableTrackingBuffer.prototype.readUInt16BE = function() {
    var length;
    length = 2;
    this.assertEnoughLeftFor(length);
    this.position += length;
    return this.buffer.readUInt16BE(this.position - length);
  };

  ReadableTrackingBuffer.prototype.readUInt32LE = function() {
    var length;
    length = 4;
    this.assertEnoughLeftFor(length);
    this.position += length;
    return this.buffer.readUInt32LE(this.position - length);
  };

  ReadableTrackingBuffer.prototype.readUInt32BE = function() {
    var length;
    length = 4;
    this.assertEnoughLeftFor(length);
    this.position += length;
    return this.buffer.readUInt32BE(this.position - length);
  };

  ReadableTrackingBuffer.prototype.readInt8 = function() {
    var length, value;
    length = 1;
    this.assertEnoughLeftFor(length);
    this.position += length;
    return value = this.buffer.readInt8(this.position - length);
  };

  ReadableTrackingBuffer.prototype.readInt16LE = function() {
    var length;
    length = 2;
    this.assertEnoughLeftFor(length);
    this.position += length;
    return this.buffer.readInt16LE(this.position - length);
  };

  ReadableTrackingBuffer.prototype.readInt16BE = function() {
    var length;
    length = 2;
    this.assertEnoughLeftFor(length);
    this.position += length;
    return this.buffer.readInt16BE(this.position - length);
  };

  ReadableTrackingBuffer.prototype.readInt32LE = function() {
    var length;
    length = 4;
    this.assertEnoughLeftFor(length);
    this.position += length;
    return this.buffer.readInt32LE(this.position - length);
  };

  ReadableTrackingBuffer.prototype.readInt32BE = function() {
    var length;
    length = 4;
    this.assertEnoughLeftFor(length);
    this.position += length;
    return this.buffer.readInt32BE(this.position - length);
  };

  ReadableTrackingBuffer.prototype.readFloatLE = function() {
    var length;
    length = 4;
    this.assertEnoughLeftFor(length);
    this.position += length;
    return this.buffer.readFloatLE(this.position - length);
  };

  ReadableTrackingBuffer.prototype.readDoubleLE = function() {
    var length;
    length = 8;
    this.assertEnoughLeftFor(length);
    this.position += length;
    return this.buffer.readDoubleLE(this.position - length);
  };

  ReadableTrackingBuffer.prototype.readUInt24LE = function() {
    var length, val;
    length = 3;
    this.assertEnoughLeftFor(length);
    val |= this.buffer[this.position + 1] << 8;
    val |= this.buffer[this.position];
    val = val + (this.buffer[this.position + 2] << 16 >>> 0);
    this.position += length;
    return val;
  };

  ReadableTrackingBuffer.prototype.readUInt40LE = function() {
    var high, low;
    low = this.readBuffer(4).readUInt32LE(0);
    high = Buffer.concat([this.readBuffer(1), new Buffer([0x00, 0x00, 0x00])]).readUInt32LE(0);
    return low + (0x100000000 * high);
  };

  ReadableTrackingBuffer.prototype.readUInt64LE = function() {
    var high, low;
    low = this.readUInt32LE();
    high = this.readUInt32LE();
    if (high >= (2 << (53 - 32))) {
      console.warn("Read UInt64LE > 53 bits : high=" + high + ", low=" + low);
    }
    return low + (0x100000000 * high);
  };

  ReadableTrackingBuffer.prototype.readUNumeric64LE = function() {
    var high, low;
    low = this.readUInt32LE();
    high = this.readUInt32LE();
    return low + (0x100000000 * high);
  };

  ReadableTrackingBuffer.prototype.readUNumeric96LE = function() {
    var dword1, dword2, dword3;
    dword1 = this.readUInt32LE();
    dword2 = this.readUInt32LE();
    dword3 = this.readUInt32LE();
    return dword1 + (0x100000000 * dword2) + (0x100000000 * 0x100000000 * dword3);
  };

  ReadableTrackingBuffer.prototype.readUNumeric128LE = function() {
    var dword1, dword2, dword3, dword4;
    dword1 = this.readUInt32LE();
    dword2 = this.readUInt32LE();
    dword3 = this.readUInt32LE();
    dword4 = this.readUInt32LE();
    return dword1 + (0x100000000 * dword2) + (0x100000000 * 0x100000000 * dword3) + (0x100000000 * 0x100000000 * 0x100000000 * dword4);
  };

  ReadableTrackingBuffer.prototype.readString = function(length, encoding) {
    encoding || (encoding = this.encoding);
    this.assertEnoughLeftFor(length);
    this.position += length;
    return this.buffer.toString(encoding, this.position - length, this.position);
  };

  ReadableTrackingBuffer.prototype.readBVarchar = function(encoding) {
    var length, multiplier;
    encoding || (encoding = this.encoding);
    multiplier = encoding === 'ucs2' ? 2 : 1;
    length = this.readUInt8() * multiplier;
    return this.readString(length, encoding);
  };

  ReadableTrackingBuffer.prototype.readUsVarchar = function(encoding) {
    var length, multiplier;
    encoding || (encoding = this.encoding);
    multiplier = encoding === 'ucs2' ? 2 : 1;
    length = this.readUInt16LE() * multiplier;
    return this.readString(length, encoding);
  };

  ReadableTrackingBuffer.prototype.readBuffer = function(length) {
    this.assertEnoughLeftFor(length);
    this.position += length;
    return this.buffer.slice(this.position - length, this.position);
  };

  ReadableTrackingBuffer.prototype.readArray = function(length) {
    return Array.prototype.slice.call(this.readBuffer(length), 0, length);
  };

  ReadableTrackingBuffer.prototype.readAsStringBigIntLE = function(length) {
    this.assertEnoughLeftFor(length);
    this.position += length;
    return convertLEBytesToString(this.buffer.slice(this.position - length, this.position));
  };

  ReadableTrackingBuffer.prototype.readAsStringInt64LE = function(length) {
    return this.readAsStringBigIntLE(8);
  };

  return ReadableTrackingBuffer;

})();

module.exports = ReadableTrackingBuffer;
