// Huffman decode tables for the decode pipeline: per-symbol code lengths in,
// a zlib-style chunked lookup table out. Shared by the streaming `Inflater`
// and the in-memory `MemDecoder`.

///|
let max_code_len = 16

///|
let huffman_chunk_bits = 9

///|
let huffman_value_shift = 4

///|
/// zlib-style chunked Huffman decode table. `chunk & 0xF` is the code length,
/// `chunk >> 4` is the value (or a link-table index for codes wider than 9 bits).
priv struct HuffmanDecoder {
  mut min : Int
  mut chunks : Array[UInt]
  mut links : Array[Array[UInt]]
  mut link_mask : UInt
}

///|
fn HuffmanDecoder::new() -> HuffmanDecoder {
  { min: 0, chunks: Array::make(512, 0U), links: [], link_mask: 0 }
}

///|
/// Build the decode table from per-symbol code lengths. Returns false if the
/// lengths do not form a complete (or valid degenerate) Huffman tree.
fn HuffmanDecoder::initialize(
  self : HuffmanDecoder,
  lengths : ArrayView[Int],
) -> Bool {
  if self.min != 0 {
    self.min = 0
    self.chunks = Array::make(512, 0U)
    self.links = []
    self.link_mask = 0
  }
  let count = Array::make(max_code_len, 0)
  let mut min = 0
  let mut max = 0
  for n in lengths {
    if n == 0 {
      continue
    }
    if min == 0 || n < min {
      min = n
    }
    if n > max {
      max = n
    }
    count[n] = count[n] + 1
  }
  if max == 0 {
    return true
  }
  let mut code = 0
  let nextcode = Array::make(max_code_len, 0)
  for i in min..<=max {
    code = code << 1
    nextcode[i] = code
    code = code + count[i]
  }
  if code != 1 << max && !(code == 1 && max == 1) {
    return false
  }
  self.min = min
  if max > huffman_chunk_bits {
    let num_links = 1 << (max - huffman_chunk_bits)
    self.link_mask = (num_links - 1).reinterpret_as_uint()
    let link = nextcode[huffman_chunk_bits + 1] >> 1
    self.links = Array::make(512 - link, ([] : Array[UInt]))
    for j in link..<512 {
      let mut reverse = reverse16((j & 0xffff).reinterpret_as_uint()).reinterpret_as_int()
      reverse = reverse >> (16 - huffman_chunk_bits)
      let off = j - link
      self.chunks[reverse] = (off.reinterpret_as_uint() << huffman_value_shift) |
        (huffman_chunk_bits + 1).reinterpret_as_uint()
      self.links[off] = Array::make(num_links, 0U)
    }
  }
  for idx, n in lengths {
    if n == 0 {
      continue
    }
    let code = nextcode[n]
    nextcode[n] = nextcode[n] + 1
    let chunk = (idx << huffman_value_shift).reinterpret_as_uint() |
      n.reinterpret_as_uint()
    let mut reverse = reverse16((code & 0xffff).reinterpret_as_uint()).reinterpret_as_int()
    reverse = reverse >> (16 - n)
    if n <= huffman_chunk_bits {
      for off = reverse; off < self.chunks.length(); off = off + (1 << n) {
        self.chunks[off] = chunk
      }
    } else {
      let j = reverse & 0x1FF
      let value = (self.chunks[j] >> huffman_value_shift).reinterpret_as_int()
      let linktab = self.links[value]
      reverse = reverse >> huffman_chunk_bits
      for off = reverse
          off < linktab.length()
          off = off + (1 << (n - huffman_chunk_bits)) {
        linktab[off] = chunk
      }
    }
  }
  true
}

///|
/// The fixed literal/length Huffman table (RFC 1951 ยง3.2.6), built from its
/// canonical code lengths so we never transcribe a precomputed table.
fn make_fixed_huffman_decoder() -> HuffmanDecoder {
  let lengths = Array::make(288, 0)
  for i in 0..<144 {
    lengths[i] = 8
  }
  for i in 144..<256 {
    lengths[i] = 9
  }
  for i in 256..<280 {
    lengths[i] = 7
  }
  for i in 280..<288 {
    lengths[i] = 8
  }
  let h = HuffmanDecoder::new()
  let _ = h.initialize(lengths[:])
  h
}

///|
let fixed_huffman_decoder : HuffmanDecoder = make_fixed_huffman_decoder()