// ignore the shims

// the original (slow) version
var Buffer1 = (function() {
  var assert = {};
  var fail = function() { throw new Error('assertion failed'); };
  var Buffer = function() { this.length = 100; };

  Buffer.prototype.writeUInt32 = function(value, offset, endian) {
    var buffer = this;

    assert.ok(value !== undefined && value !== null,
      'missing value');

    assert.ok(endian !== undefined && endian !== null,
      'missing endian');

    assert.ok(endian == 'big' || endian == 'little',
      'bad endian value');

    assert.ok(offset !== undefined && offset !== null,
      'missing offset');

    assert.ok(offset + 3 < buffer.length,
      'trying to read beyond buffer length');

    verifuint(value, 0xffffffff);
    if (endian == 'big') {
      buffer[offset] = (value >>> 24) & 0xff;
      buffer[offset + 1] = (value >>> 16) & 0xff;
      buffer[offset + 2] = (value >>> 8) & 0xff;
      buffer[offset + 3] = value & 0xff;
    } else {
      buffer[offset + 3] = (value >>> 24) & 0xff;
      buffer[offset + 2] = (value >>> 16) & 0xff;
      buffer[offset + 1] = (value >>> 8) & 0xff;
      buffer[offset] = value & 0xff;
    }
  };

  assert.ok = function ok(value, message) {
    if (!!!value) fail(value, true, message, '==', assert.ok);
  };

  function verifuint(value, max) {
    assert.ok(typeof (value) == 'number',
      'cannot write a non-number as a number');

    assert.ok(value >= 0,
      'specified a negative value for writing an unsigned value');

    assert.ok(value <= max, 'value is larger than maximum value for type');

    assert.ok(Math.floor(value) === value, 'value has a fractional component');
  }

  return Buffer;
})();

// the optimized version
var Buffer2 = (function() {
  var assert = {};
  var fail = function() { throw new Error('assertion failed'); };
  var Buffer = function() { this.length = 100; };

  Buffer.prototype.writeUInt32 = function(value, offset, little) {
    // utilizing type coercion is more than 
    // 3x faster than two comparisons
    assert.ok(value != null, 'missing value');

    // removed endian assertions - big endian by default

    //assert.ok(offset != null, 'missing offset');

    // `NaN < x` *always* returns false,
    // so we can, in theory, drop the 
    // above assertion and just use:
    assert.ok(offset + 3 < this.length,
      'trying to read beyond buffer length');

    verifuint(value, 0xffffffff);

    if (!little) {
      this[offset] = (value >>> 24) & 0xff;
      this[offset + 1] = (value >>> 16) & 0xff;
      this[offset + 2] = (value >>> 8) & 0xff;
      this[offset + 3] = value & 0xff;
    } else {
      this[offset + 3] = (value >>> 24) & 0xff;
      this[offset + 2] = (value >>> 16) & 0xff;
      this[offset + 1] = (value >>> 8) & 0xff;
      this[offset] = value & 0xff;
    }
  };

  function verifuint(value, max) {
    assert.ok(typeof value === 'number',
      'cannot write a non-number as a number');

    assert.ok(value >= 0,
      'specified a negative value for writing an unsigned value');

    assert.ok(value <= max, 'value is larger than maximum value for type');

    // nearly 4x faster than calling Math.floor
    assert.ok(value % 1 === 0, 'value has a fractional component');
  }

  assert.ok = function ok(value, message) {
    // there is no reason for 3 bangs here
    if (!value) fail(value, true, message, '==', assert.ok);
  };

  return Buffer;
})();

// benchmarks
(function() {
  var b1 = new Buffer1(),
      b2 = new Buffer2();

  var times = 1000000;
  (function() {
    var start = Date.now();
    for (var i = times; i--;) {
      b1.writeUInt32(10, 0, 'big');
    }
    console.log('one: %sms', Date.now() - start);
  })();

  (function() {
    var start = Date.now();
    for (var i = times; i--;) {
      b2.writeUInt32(10, 0, false);
    }
    console.log('two: %sms', Date.now() - start);
  })();
})();