const AbstractStream = require('streams/abstract-stream')
const NotEnoughDataError = require('lib/not-enough-data-error')

class DecodeStream extends AbstractStream {
  constructor(options = {}) {
    let buf = null

    if (Buffer.isBuffer(options)) {
      buf = options
      options = {}
    }

    options.readableObjectMode = true
    options.writableObjectMode = false
    super(options)

    if (buf !== null) {
      this.append(buf)
    }
  }

  readBuffer(size) {
    assertSize(size, this.length)

    const buf = this.slice(0, size)
    this.consume(size)

    return buf
  }
}

const fixedMethods = {
  readDoubleBE: 8,
  readDoubleLE: 8,
  readFloatBE: 4,
  readFloatLE: 4,
  readInt32BE: 4,
  readInt32LE: 4,
  readUInt32BE: 4,
  readUInt32LE: 4,
  readInt16BE: 2,
  readInt16LE: 2,
  readUInt16BE: 2,
  readUInt16LE: 2,
  readInt8: 1,
  readUInt8: 1,
}

const metaMethods = ['readIntBE', 'readIntLE', 'readUIntBE', 'readUIntLE']

Object.keys(fixedMethods).forEach(method => {
  DecodeStream.prototype[method] = function() {
    const bytes = fixedMethods[method]

    assertSize(bytes, this.length)
    const res = this.buffer[method]()
    this.consume(bytes)

    return res
  }
})

metaMethods.forEach(method => {
  DecodeStream.prototype[method] = function(size) {
    assertSize(size, this.length)

    const res = this.buffer[method](size)
    this.consume(size)
    return res
  }
})

module.exports = DecodeStream

function assertSize(size, length) {
  if (size > length) {
    throw new NotEnoughDataError(size, length)
  }
}


const AbstractStream = require('streams/abstract-stream')
const NotEnoughDataError = require('lib/not-enough-data-error')

class DecodeStream extends AbstractStream {
  constructor(options = {}) {
    let buf = null

    if (Buffer.isBuffer(options)) {
      buf = options
      options = {}
    }

    options.readableObjectMode = true
    options.writableObjectMode = false
    super(options)

    if (buf !== null) {
      this.append(buf)
    }
  }

  readBuffer(size) {
    assertSize(size, this.length)

    const buf = this.slice(0, size)
    this.consume(size)

    return buf
  }
}

const fixedMethods = {
  readDoubleBE: 8,
  readDoubleLE: 8,
  readFloatBE: 4,
  readFloatLE: 4,
  readInt32BE: 4,
  readInt32LE: 4,
  readUInt32BE: 4,
  readUInt32LE: 4,
  readInt16BE: 2,
  readInt16LE: 2,
  readUInt16BE: 2,
  readUInt16LE: 2,
  readInt8: 1,
  readUInt8: 1,
}

const metaMethods = ['readIntBE', 'readIntLE', 'readUIntBE', 'readUIntLE']

Object.keys(fixedMethods).forEach(method => {
  DecodeStream.prototype[method] = function() {
    const bytes = fixedMethods[method]

    assertSize(bytes, this.length)
    const res = this.buffer[method](0)
    this.consume(bytes)

    return res
  }
})

metaMethods.forEach(method => {
  DecodeStream.prototype[method] = function(size) {
    assertSize(size, this.length)

    const res = this.buffer[method](size, 0)
    this.consume(size)
    return res
  }
})

module.exports = DecodeStream

function assertSize(size, length) {
  if (size > length) {
    throw new NotEnoughDataError(size, length)
  }
}


optimise argument adaptation.