// moonmp3-encoder — pure MoonBit MP3 encoder.
// Copyright 2026 Sakuraqwq1
// Licensed under the Apache License, Version 2.0.

// Count1-region Huffman coding, table B. ISO/IEC 11172-3 Table B.7:
// each four coefficients are represented by a four-bit mask of the non-zero
// positions, followed by one sign bit per non-zero coefficient. The codeword
// is the bitwise complement of that mask. Values are restricted to -1/0/1.
//
// This deliberately small subset is the first vertical slice of the encoder.
// It lets the bitstream and frame assembly be verified independently of the
// analysis filterbank and the larger big-values Huffman tables.

///|
/// Errors reported by the count1 writer and its fixed-spectrum test encoder.
pub suberror Count1Error {
  BadLength(Int32)
  BadValue(Int32)
  BadChannels(Int32)
  BadFrames(Int32)
  BadGain(Int32)
  FrameOverflow(Int32)
}

///|
/// Number of bits needed for a count1-region sequence.
///
/// Every group of four coefficients costs four bits for its mask, plus one
/// sign bit for each non-zero coefficient. The length must be a non-zero
/// multiple of four and every value must be -1, 0 or 1.
pub fn count1_bits(values : Array[Int32]) -> Int32 raise Count1Error {
  if values.length() == 0 || values.length() % 4 != 0 {
    raise BadLength(values.length())
  }
  let mut bits = values.length()
  for value in values {
    if value < -1 || value > 1 {
      raise BadValue(value)
    }
    if value != 0 {
      bits = bits + 1
    }
  }
  bits
}

///|
/// Write a count1-region sequence using Huffman table B.
///
/// The return value is the exact number of bits written and is suitable for
/// `part2_3_length` when no scalefactors are transmitted.
pub fn write_count1(
  w : @bits.BitWriter,
  values : Array[Int32],
) -> Int32 raise Count1Error {
  let bits = count1_bits(values)
  for base = 0; base < values.length(); base = base + 4 {
    let mut mask = 0
    for offset = 0; offset < 4; offset = offset + 1 {
      if values[base + offset] != 0 {
        mask = mask | (1 << (3 - offset))
      }
    }
    w.write_bits((15 - mask).to_int64(), 4)
    for offset = 0; offset < 4; offset = offset + 1 {
      let value = values[base + offset]
      if value != 0 {
        w.write_bit(if value < 0 { 1 } else { 0 })
      }
    }
  }
  bits
}

///|
/// Side information for one count1-only granule with no scalefactor bytes.
pub fn GranuleInfo::count1(
  part2_3_length : Int32,
  global_gain : Int32,
) -> GranuleInfo {
  {
    part2_3_length,
    big_values: 0,
    global_gain,
    scalefac_compress: 0,
    window_switching_flag: 0,
    block_type: 0,
    mixed_block_flag: 0,
    table_select0: 0,
    table_select1: 0,
    table_select2: 0,
    subblock_gain0: 0,
    subblock_gain1: 0,
    subblock_gain2: 0,
    region0_count: 0,
    region1_count: 0,
    preflag: 0,
    scalefac_scale: 0,
    count1table_select: 1,
  }
}