// Generated by CoffeeScript 1.7.1
var SHIFT_LEFT_32, SHIFT_RIGHT_32, UNKNOWN_PLP_LEN, WritableTrackingBuffer, bigint, buffertools;

bigint = require('./bigint');

buffertools = require('../buffertools');

SHIFT_LEFT_32 = (1 << 16) * (1 << 16);

SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32;

UNKNOWN_PLP_LEN = new Buffer([0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);


/*
  A Buffer-like class that tracks position.

  As values are written, the position advances by the size of the written data.
  When writing, automatically allocates new buffers if there's not enough space.
 */

WritableTrackingBuffer = (function() {
  function WritableTrackingBuffer(initialSize, encoding, doubleSizeGrowth) {
    this.initialSize = initialSize;
    this.encoding = encoding;
    this.doubleSizeGrowth = doubleSizeGrowth;
    this.doubleSizeGrowth || (this.doubleSizeGrowth = false);
    this.encoding || (this.encoding = 'ucs2');
    this.buffer = new Buffer(this.initialSize);
    this.position = 0;
    this.__defineGetter__("data", function() {
      this.newBuffer(0);
      return this.compositeBuffer;
    });
  }

  WritableTrackingBuffer.prototype.copyFrom = function(buffer) {
    var length;
    length = buffer.length;
    this.makeRoomFor(length);
    buffer.copy(this.buffer, this.position);
    return this.position += length;
  };

  WritableTrackingBuffer.prototype.makeRoomFor = function(requiredLength) {
    var size;
    if (this.buffer.length - this.position < requiredLength) {
      if (this.doubleSizeGrowth) {
        size = this.buffer.length * 2;
        while (size < requiredLength) {
          size *= 2;
        }
        return this.newBuffer(size);
      } else {
        return this.newBuffer(requiredLength);
      }
    }
  };

  WritableTrackingBuffer.prototype.newBuffer = function(size) {
    var buffer;
    size || (size = this.initialSize);
    buffer = this.buffer.slice(0, this.position);
    if (this.compositeBuffer) {
      this.compositeBuffer = Buffer.concat([this.compositeBuffer, buffer]);
    } else {
      this.compositeBuffer = buffer;
    }
    this.buffer = new Buffer(size);
    return this.position = 0;
  };

  WritableTrackingBuffer.prototype.writeUInt8 = function(value) {
    var length;
    length = 1;
    this.makeRoomFor(length);
    this.buffer.writeUInt8(value, this.position);
    return this.position += length;
  };

  WritableTrackingBuffer.prototype.writeUInt16LE = function(value) {
    var length;
    length = 2;
    this.makeRoomFor(length);
    this.buffer.writeUInt16LE(value, this.position);
    return this.position += length;
  };

  WritableTrackingBuffer.prototype.writeUShort = function(value) {
    return this.writeUInt16LE(value);
  };

  WritableTrackingBuffer.prototype.writeUInt16BE = function(value) {
    var length;
    length = 2;
    this.makeRoomFor(length);
    this.buffer.writeUInt16BE(value, this.position);
    return this.position += length;
  };

  WritableTrackingBuffer.prototype.writeUInt24LE = function(value) {
    var length;
    length = 3;
    this.makeRoomFor(length);
    this.buffer[this.position + 2] = (value >>> 16) & 0xff;
    this.buffer[this.position + 1] = (value >>> 8) & 0xff;
    this.buffer[this.position] = value & 0xff;
    return this.position += length;
  };

  WritableTrackingBuffer.prototype.writeUInt32LE = function(value) {
    var length;
    length = 4;
    this.makeRoomFor(length);
    this.buffer.writeUInt32LE(value, this.position);
    return this.position += length;
  };

  WritableTrackingBuffer.prototype.writeUInt64LE = function(value) {
    var high, low;
    low = value % 0x100000000;
    high = Math.floor(value / 0x100000000);
    this.writeUInt32LE(low);
    return this.writeUInt32LE(high);
  };

  WritableTrackingBuffer.prototype.writeInt64LE = function(value) {
    var buf;
    buf = bigint.numberToInt64LE(value);
    return this.copyFrom(buf);
  };

  WritableTrackingBuffer.prototype.writeUInt32BE = function(value) {
    var length;
    length = 4;
    this.makeRoomFor(length);
    this.buffer.writeUInt32BE(value, this.position);
    return this.position += length;
  };

  WritableTrackingBuffer.prototype.writeUInt40LE = function(value) {
    this.writeInt32LE(value & -1);
    return this.writeUInt8(Math.floor(value * SHIFT_RIGHT_32));
  };

  WritableTrackingBuffer.prototype.writeUInt64LE = function(value) {
    this.writeInt32LE(value & -1);
    return this.writeUInt32LE(Math.floor(value * SHIFT_RIGHT_32));
  };

  WritableTrackingBuffer.prototype.writeInt8 = function(value) {
    var length;
    length = 1;
    this.makeRoomFor(length);
    this.buffer.writeInt8(value, this.position);
    return this.position += length;
  };

  WritableTrackingBuffer.prototype.writeInt16LE = function(value) {
    var length;
    length = 2;
    this.makeRoomFor(length);
    this.buffer.writeInt16LE(value, this.position);
    return this.position += length;
  };

  WritableTrackingBuffer.prototype.writeInt16BE = function(value) {
    var length;
    length = 2;
    this.makeRoomFor(length);
    this.buffer.writeInt16BE(value, this.position);
    return this.position += length;
  };

  WritableTrackingBuffer.prototype.writeInt32LE = function(value) {
    var length;
    length = 4;
    this.makeRoomFor(length);
    this.buffer.writeInt32LE(value, this.position);
    return this.position += length;
  };

  WritableTrackingBuffer.prototype.writeInt32BE = function(value) {
    var length;
    length = 4;
    this.makeRoomFor(length);
    this.buffer.writeInt32BE(value, this.position);
    return this.position += length;
  };

  WritableTrackingBuffer.prototype.writeFloatLE = function(value) {
    var length;
    length = 4;
    this.makeRoomFor(length);
    this.buffer.writeFloatLE(value, this.position);
    return this.position += length;
  };

  WritableTrackingBuffer.prototype.writeDoubleLE = function(value) {
    var length;
    length = 8;
    this.makeRoomFor(length);
    this.buffer.writeDoubleLE(value, this.position);
    return this.position += length;
  };

  WritableTrackingBuffer.prototype.writeString = function(value, encoding) {
    var bytesWritten, length;
    encoding || (encoding = this.encoding);
    length = Buffer.byteLength(value, encoding);
    this.makeRoomFor(length);
    bytesWritten = this.buffer.write(value, this.position, encoding);
    this.position += length;
    return bytesWritten;
  };

  WritableTrackingBuffer.prototype.writeBVarchar = function(value, encoding) {
    this.writeUInt8(value.length);
    return this.writeString(value, encoding);
  };

  WritableTrackingBuffer.prototype.writeUsVarchar = function(value, encoding) {
    this.writeUInt16LE(value.length);
    return this.writeString(value, encoding);
  };

  WritableTrackingBuffer.prototype.writeUsVarbyte = function(value, encoding) {
    var length;
    if (encoding == null) {
      encoding = this.encoding;
    }
    if (Buffer.isBuffer(value)) {
      length = value.length;
    } else {
      value = value.toString();
      length = Buffer.byteLength(value, encoding);
    }
    this.writeUInt16LE(length);
    if (Buffer.isBuffer(value)) {
      return this.writeBuffer(value);
    } else {
      this.makeRoomFor(length);
      this.buffer.write(value, this.position, encoding);
      return this.position += length;
    }
  };

  WritableTrackingBuffer.prototype.writePLPBody = function(value, encoding) {
    var length;
    if (encoding == null) {
      encoding = this.encoding;
    }
    if (Buffer.isBuffer(value)) {
      length = value.length;
    } else {
      value = value.toString();
      length = Buffer.byteLength(value, encoding);
    }
    this.writeBuffer(UNKNOWN_PLP_LEN);
    this.writeUInt32LE(length);
    if (Buffer.isBuffer(value)) {
      this.writeBuffer(value);
    } else {
      this.makeRoomFor(length);
      this.buffer.write(value, this.position, encoding);
      this.position += length;
    }
    return this.writeUInt32LE(0);
  };

  WritableTrackingBuffer.prototype.writeBuffer = function(value) {
    var length;
    length = value.length;
    this.makeRoomFor(length);
    value.copy(this.buffer, this.position);
    return this.position += length;
  };

  WritableTrackingBuffer.prototype.writeMoney = function(value) {
    this.writeInt32LE(Math.floor(value * SHIFT_RIGHT_32));
    return this.writeInt32LE(value & -1);
  };

  return WritableTrackingBuffer;

})();

module.exports = WritableTrackingBuffer;
