import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
import { BitInputStream } from "./input.js";
const DEFAULT_BUF_SIZE = 16;
const U32 = 4294967296;
class BitOutputStream {
  buffer;
  start;
  pos;
  bit;
  bitPos;
  constructor(buffer, offset = 0) {
    this.buffer = typeof buffer === "undefined" ? new Uint8Array(DEFAULT_BUF_SIZE) : typeof buffer === "number" ? new Uint8Array(buffer) : buffer;
    this.start = offset;
    this.seek(offset);
    this.buffer[this.pos] &= ~((1 << this.bit) - 1);
  }
  get position() {
    return this.bitPos;
  }
  seek(pos) {
    if (pos < this.start || pos >= this.buffer.length << 3) {
      illegalArgs(`seek pos out of bounds: ${pos}`);
    }
    this.pos = pos >>> 3;
    this.bit = 8 - (pos & 7);
    this.bitPos = pos;
    return this;
  }
  bytes() {
    return this.buffer.slice(0, this.pos + (this.bit & 7 ? 1 : 0));
  }
  reader(from = 0) {
    return new BitInputStream(this.buffer, from, this.position);
  }
  write(x, wordSize = 1) {
    if (wordSize > 32) {
      let hi = Math.floor(x / U32);
      this.write(hi, wordSize - 32);
      this.write(x - hi * U32, 32);
    } else if (wordSize > 8) {
      let n = wordSize & -8;
      let msb = wordSize - n;
      if (msb > 0) {
        this._write(x >>> n, msb);
      }
      n -= 8;
      while (n >= 0) {
        this._write(x >>> n, 8);
        n -= 8;
      }
    } else {
      this._write(x, wordSize);
    }
    return this;
  }
  writeWords(input, wordSize = 8) {
    let iter = input[Symbol.iterator]();
    let v;
    while (v = iter.next(), !v.done) {
      this.write(v.value, wordSize);
    }
  }
  writeBit(x) {
    this.bit--;
    this.buffer[this.pos] = this.buffer[this.pos] & ~(1 << this.bit) | x << this.bit;
    if (this.bit === 0) {
      this.ensureSize();
      this.bit = 8;
    }
    this.bitPos++;
    return this;
  }
  _write(x, wordSize) {
    x &= (1 << wordSize) - 1;
    let buf = this.buffer;
    let pos = this.pos;
    let bit = this.bit;
    let b = bit - wordSize;
    let m = bit < 8 ? ~((1 << bit) - 1) : 0;
    if (b >= 0) {
      m |= (1 << b) - 1;
      buf[pos] = buf[pos] & m | x << b & ~m;
      if (b === 0) {
        this.ensureSize();
        this.bit = 8;
      } else {
        this.bit = b;
      }
    } else {
      this.bit = bit = 8 + b;
      buf[pos] = buf[pos] & m | x >>> -b & ~m;
      this.ensureSize();
      this.buffer[this.pos] = this.buffer[this.pos] & (1 << bit) - 1 | x << bit & 255;
    }
    this.bitPos += wordSize;
    return this;
  }
  ensureSize() {
    if (++this.pos === this.buffer.length) {
      let b = new Uint8Array(this.buffer.length << 1);
      b.set(this.buffer);
      this.buffer = b;
    }
  }
}
export {
  BitOutputStream
};
