// Stream and meta-block headers (RFC 7932 sections 9.1 and 9.2).

///|
fn Decoder::stream_header(self : Decoder) -> Unit raise Stop {
  let wbits = if self.read_bits(1) == 0 {
    16
  } else {
    let n = self.read_bits(3)
    if n != 0 {
      17 + n
    } else {
      let m = self.read_bits(3)
      if m == 1 {
        raise corrupt("large-window streams are not RFC 7932")
      }
      if m != 0 {
        8 + m
      } else {
        17
      }
    }
  }
  if wbits > self.max_window_bits {
    raise Fail(
      WindowTooLarge,
      "the stream needs a \{1 << wbits}-byte window, over the limit of \{1 << self.max_window_bits}",
    )
  }
  self.ring_max = 1 << wbits
  self.window = self.ring_max - 16
  self.state = MetaHeader
}

///|
fn Decoder::meta_header(self : Decoder) -> Unit raise Stop {
  let is_last = self.read_bits(1) == 1
  if is_last && self.read_bits(1) == 1 {
    // ISLASTEMPTY
    self.is_last = true
    self.meta_remaining = 0
    self.state = MetaDone
    return
  }
  let nibbles = self.read_bits(2)
  if nibbles == 3 {
    // A metadata block.
    if self.read_bits(1) != 0 {
      raise corrupt("reserved bit set")
    }
    let count = self.read_bits(2)
    let mut length = 0
    for i in 0.. 1 && byte == 0 {
        raise corrupt("metadata length has a needless zero byte")
      }
      length = length | (byte << (8 * i))
    }
    self.skip_padding()
    self.is_last = is_last
    self.meta_remaining = if count == 0 { 0 } else { length + 1 }
    self.state = Metadata
    return
  }
  let count = nibbles + 4
  let mut length = 0
  for i in 0.. 4 && nibble == 0 {
      raise corrupt("meta-block length has a needless zero nibble")
    }
    length = length | (nibble << (4 * i))
  }
  let uncompressed = !is_last && self.read_bits(1) == 1
  self.is_last = is_last
  self.meta_remaining = length + 1
  if uncompressed {
    self.skip_padding()
    self.state = Uncompressed
    return
  }
  for c in 0..<3 {
    self.num_types[c] = 1
    self.block_type[c] = 0
    self.prev_block_type[c] = 1
    self.block_len[c] = ENDLESS_BLOCK
  }
  self.cat = 0
  self.state = NumBlockTypes
}

///|
/// Skips metadata bytes.
fn Decoder::metadata(self : Decoder) -> Status? raise Stop {
  while self.meta_remaining > 0 {
    if self.nbits >= 8 || self.stash_pos < self.stash.length() {
      self.next_aligned_byte() |> ignore
      self.meta_remaining -= 1
      self.checkpoint()
      continue
    }
    let n = self.meta_remaining.min(self.view.length() - self.in_pos)
    if n == 0 {
      raise NeedInput
    }
    self.in_pos += n
    self.meta_remaining -= n
    self.checkpoint()
  }
  self.state = MetaDone
  None
}

///|
/// Copies an uncompressed meta-block.
fn Decoder::uncompressed(self : Decoder) -> Status? raise Stop {
  while self.meta_remaining > 0 {
    let want = self.meta_remaining.min(1 << 16)
    if self.free_space() < want {
      self.drain()
    }
    let room = want.min(self.free_space())
    if room == 0 {
      return Some(NeedMoreOutput)
    }
    self.ensure_space(room) |> ignore
    if self.nbits >= 8 || self.stash_pos < self.stash.length() {
      self.put(self.next_aligned_byte())
      self.meta_remaining -= 1
      self.checkpoint()
      continue
    }
    let n = room.min(self.view.length() - self.in_pos)
    if n == 0 {
      raise NeedInput
    }
    self.copy_input(n)
    self.meta_remaining -= n
    self.checkpoint()
  }
  self.state = MetaDone
  None
}

///|
fn Decoder::num_block_types(self : Decoder) -> Unit raise Stop {
  let n = self.read_var_len8() + 1
  self.num_types[self.cat] = n
  if n >= 2 {
    self.type_codes[self.cat].reset(1, n + 2)
    self.count_codes[self.cat].reset(1, NUM_BLOCK_COUNT_CODES)
    self.code.start(n + 2, self.type_codes[self.cat], 0)
    self.state = BlockTypeCode
  } else {
    self.next_category()
  }
}

///|
/// A block count: a symbol of category `cat`'s count code and extra bits.
fn Decoder::read_block_count(self : Decoder, cat : Int32) -> Int32 raise Stop {
  let sym = self.read_symbol(self.count_codes[cat], 0)
  block_count_base[sym] + self.read_bits(block_count_extra[sym])
}

///|
fn Decoder::next_category(self : Decoder) -> Unit {
  self.cat += 1
  self.state = if self.cat < 3 { NumBlockTypes } else { DistanceParams }
}

///|
fn Decoder::distance_params(self : Decoder) -> Unit raise Stop {
  let npostfix = self.read_bits(2)
  let ndirect = self.read_bits(4) << npostfix
  self.npostfix = npostfix
  self.ndirect = ndirect
  self.index = 0
  self.state = ContextModes
}

///|
fn Decoder::context_mode(self : Decoder) -> Unit raise Stop {
  self.context_modes[self.index] = self.read_bits(2)
  self.index += 1
  if self.index == self.num_types[0] {
    self.cat = 0
    self.state = NumTrees
  }
}

///|
/// NTREESL (`cat` 0) or NTREESD (`cat` 2).
fn Decoder::num_trees(self : Decoder) -> Unit raise Stop {
  let trees = self.read_var_len8() + 1
  let (map, size) = if self.cat == 0 {
    self.lit_trees_count = trees
    (self.lit_context_map, 64 * self.num_types[0])
  } else {
    self.dist_trees_count = trees
    (self.dist_context_map, 4 * self.num_types[2])
  }
  self.map_size = size
  if trees >= 2 {
    self.state = ContextMapHeader
  } else {
    map.fill(b'\x00', end=size)
    self.after_context_map()
  }
}

///|
fn Decoder::context_map_header(self : Decoder) -> Unit raise Stop {
  let rle_max = if self.read_bits(1) == 1 { self.read_bits(4) + 1 } else { 0 }
  let trees = if self.cat == 0 {
    self.lit_trees_count
  } else {
    self.dist_trees_count
  }
  self.map_rle_max = rle_max
  self.index = 0
  self.map_code.reset(1, trees + rle_max)
  self.code.start(trees + rle_max, self.map_code, 0)
  self.state = ContextMapCode
}

///|
fn Decoder::context_map_entry(self : Decoder) -> Unit raise Stop {
  let map = if self.cat == 0 {
    self.lit_context_map
  } else {
    self.dist_context_map
  }
  let sym = self.read_symbol(self.map_code, 0)
  if sym == 0 {
    map[self.index] = b'\x00'
    self.index += 1
  } else if sym <= self.map_rle_max {
    let run = (1 << sym) + self.read_bits(sym)
    if self.index + run > self.map_size {
      raise corrupt("context map run past its end")
    }
    map.fill(b'\x00', start=self.index, end=self.index + run)
    self.index += run
  } else {
    map[self.index] = (sym - self.map_rle_max).to_byte()
    self.index += 1
  }
  if self.index == self.map_size {
    self.state = ContextMapImtf
  }
}

///|
fn Decoder::context_map_imtf(self : Decoder) -> Unit raise Stop {
  if self.read_bits(1) == 1 {
    let map = if self.cat == 0 {
      self.lit_context_map
    } else {
      self.dist_context_map
    }
    let mtf = FixedArray::makei(256, i => i.to_byte())
    for i in 0.. 0; j = j - 1 {
        mtf[j] = mtf[j - 1]
      }
      mtf[0] = value
    }
  }
  self.after_context_map()
}

///|
fn Decoder::after_context_map(self : Decoder) -> Unit {
  if self.cat == 0 {
    self.cat = 2
    self.state = NumTrees
  } else {
    self.cat = 0
    self.start_trees()
  }
}

///|
/// The group of trees of category `cat`, its tree count and alphabet.
fn Decoder::trees(self : Decoder, cat : Int32) -> (Group, Int32, Int32) {
  match cat {
    0 => (self.lit_trees, self.lit_trees_count, NUM_LITERALS)
    1 => (self.cmd_trees, self.num_types[1], MAX_ALPHABET)
    _ =>
      (
        self.dist_trees,
        self.dist_trees_count,
        16 + self.ndirect + (48 << self.npostfix),
      )
  }
}

///|
/// Starts reading the trees of category `cat`.
fn Decoder::start_trees(self : Decoder) -> Unit {
  let (group, count, alphabet) = self.trees(self.cat)
  group.reset(count, alphabet)
  self.index = 0
  self.code.start(alphabet, group, 0)
  self.state = TreeCodes
}

///|
fn Decoder::tree_code(self : Decoder) -> Unit raise Stop {
  guard self.read_code() else { return }
  let (group, count, alphabet) = self.trees(self.cat)
  self.index += 1
  if self.index < count {
    self.code.start(alphabet, group, self.index)
  } else if self.cat < 2 {
    self.cat += 1
    self.start_trees()
  } else {
    self.lit_mode = self.context_modes[0]
    self.lit_map_offset = 0
    self.dist_map_offset = 0
    self.state = CommandStart
  }
}