/// Tile-owned palette CDFs and direct-MI neighbor colors. Each recorded color
/// array is immutable after publication; a new block replaces the current
/// arrays. U is the shared chroma cache base; V has no neighbor cache.

///|
priv struct Av1PaletteState {
  cols : Int
  rows : Int
  y_mode : Array[Array[Array[Int]]]
  uv_mode : Array[Array[Int]]
  y_size : Array[Array[Int]]
  uv_size : Array[Array[Int]]
  y_index : Array[Array[Array[Int]]]
  uv_index : Array[Array[Array[Int]]]
  y_neighbors : Array[Array[Int]]
  u_neighbors : Array[Array[Int]]
  mut y_colors : Array[Int]
  mut u_colors : Array[Int]
  mut v_colors : Array[Int]
}

///|
/// cols/rows are the tile's already validated, padded MI dimensions. Index
/// CDFs use [palette size - 2][context 0..4], each with size+1 entries.
fn av1_palette_state(cols : Int, rows : Int) -> Av1PaletteState {
  {
    cols,
    rows,
    y_mode: av1_palette_y_mode_cdfs(),
    uv_mode: av1_palette_uv_mode_cdfs(),
    y_size: av1_palette_y_size_cdfs(),
    uv_size: av1_palette_uv_size_cdfs(),
    y_index: av1_palette_y_index_cdfs(),
    uv_index: av1_palette_uv_index_cdfs(),
    y_neighbors: Array::makei(cols * rows, _ => []),
    u_neighbors: Array::makei(cols * rows, _ => []),
    y_colors: [],
    u_colors: [],
    v_colors: [],
  }
}

///|
/// Entropy-coded literal, distinct from the MSAC raw-input refill helper.
/// Callers supply a syntax-defined count in 0..12.
fn av1_palette_literal(decoder : Av1SymbolDecoder, count : Int) -> Int {
  let mut value = 0
  for _ in 0.. Int? {
  if n < 1 || n > 8 {
    return None
  }
  let bits = av1_msac_floor_log2(n) + 1
  let cutoff = (1 << bits) - n
  let value = av1_palette_literal(decoder, bits - 1)
  let result = if value < cutoff {
    value
  } else {
    2 * value - cutoff + decoder.bool()
  }
  Some(result)
}

///|
fn av1_palette_mode_context(state : Av1PaletteState, block : Av1SbBlock) -> Int {
  let row = block.row / 4
  let col = block.col / 4
  let above = row > 0 &&
    state.y_neighbors[(row - 1) * state.cols + col].length() > 0
  let left = col > 0 &&
    state.y_neighbors[row * state.cols + col - 1].length() > 0
  (if above { 1 } else { 0 }) + (if left { 1 } else { 0 })
}

///|
/// Merge sorted lists without removing duplicates: equal U base colors may
/// correspond to different V values. Only the neighbor-cache union deduplicates.
fn av1_palette_merge_colors(
  first : Array[Int],
  second : Array[Int],
) -> Array[Int] {
  let result : Array[Int] = []
  let mut i = 0
  let mut j = 0
  while i < first.length() || j < second.length() {
    if i < first.length() && (j == second.length() || first[i] <= second[j]) {
      result.push(first[i])
      i = i + 1
    } else {
      result.push(second[j])
      j = j + 1
    }
  }
  result
}

///|
/// plane is 0 for Y or 1 for U. Direct above/left MI points are used for both.
/// Every 64-luma-pixel row suppresses the above COLOR CACHE, including halfway
/// through a 128 SB. It does not suppress av1_palette_mode_context's above flag.
/// Tile origins are SB-aligned, so the tile-local row preserves this boundary.
fn av1_palette_cache(
  state : Av1PaletteState,
  block : Av1SbBlock,
  plane : Int,
) -> Array[Int] {
  let row = block.row / 4
  let col = block.col / 4
  let neighbors = if plane == 0 { state.y_neighbors } else { state.u_neighbors }
  let above = if row > 0 && block.row % 64 != 0 {
    neighbors[(row - 1) * state.cols + col]
  } else {
    []
  }
  let left = if col > 0 { neighbors[row * state.cols + col - 1] } else { [] }
  let cache : Array[Int] = []
  for color in av1_palette_merge_colors(above, left) {
    if cache.length() == 0 || cache[cache.length() - 1] != color {
      cache.push(color)
    }
  }
  cache
}

///|
/// Read Y or U: cached selections precede an independently coded sorted new
/// list. Y deltas are positive; U deltas may be zero. Clamp before shrinking
/// the next delta's bit count, exactly as decodemv.c read_palette_colors_y/uv.
fn av1_palette_read_base_colors(
  decoder : Av1SymbolDecoder,
  cache : Array[Int],
  size : Int,
  bit_depth : Int,
  is_y : Bool,
) -> Array[Int] {
  let cached : Array[Int] = []
  for color in cache {
    if cached.length() == size {
      break
    }
    if decoder.bool() != 0 {
      cached.push(color)
    }
  }
  if cached.length() == size {
    return cached
  }
  let fresh = [av1_palette_literal(decoder, bit_depth)]
  let new_count = size - cached.length()
  if new_count > 1 {
    let mut bits = bit_depth - 3 + av1_palette_literal(decoder, 2)
    let maximum = (1 << bit_depth) - 1
    while fresh.length() < new_count {
      let delta = av1_palette_literal(decoder, bits) +
        (if is_y { 1 } else { 0 })
      let value = fresh[fresh.length() - 1] + delta
      let color = if value > maximum { maximum } else { value }
      fresh.push(color)
      let range = (1 << bit_depth) - color - (if is_y { 1 } else { 0 })
      let remaining_bits = if range <= 1 {
        0
      } else {
        av1_msac_floor_log2(range - 1) + 1
      }
      if remaining_bits < bits {
        bits = remaining_bits
      }
    }
  }
  av1_palette_merge_colors(cached, fresh)
}

///|
/// V follows the final U order. Its signed deltas wrap at native bit depth;
/// they do not clip, shrink their bit count, or reorder the U/V pairs.
fn av1_palette_read_v_colors(
  decoder : Av1SymbolDecoder,
  size : Int,
  bit_depth : Int,
) -> Array[Int] {
  let colors : Array[Int] = []
  if decoder.bool() == 0 {
    for _ in 0..= modulus {
          value - modulus
        } else {
          value
        },
      )
    }
  }
  colors
}

///|
/// Publish fresh immutable Y/U color arrays at every covered MI point, also
/// clearing the cache entries of non-palette and non-chroma-owning blocks.
fn av1_palette_record(state : Av1PaletteState, block : Av1SbBlock) -> Unit {
  let row_end = if block.row / 4 + block.height / 4 < state.rows {
    block.row / 4 + block.height / 4
  } else {
    state.rows
  }
  let col_end = if block.col / 4 + block.width / 4 < state.cols {
    block.col / 4 + block.width / 4
  } else {
    state.cols
  }
  for row in (block.row / 4).. Bool {
  if !av1_tx_block_geometry_valid(block.width, block.height) ||
    block.row < 0 ||
    block.col < 0 ||
    block.row % 4 != 0 ||
    block.col % 4 != 0 ||
    block.row / 4 >= state.rows ||
    block.col / 4 >= state.cols ||
    (bit_depth != 8 && bit_depth != 10 && bit_depth != 12) ||
    y_mode < 0 ||
    y_mode > 12 ||
    uv_mode < 0 ||
    uv_mode > 13 {
    return false
  }
  state.y_colors = []
  state.u_colors = []
  state.v_colors = []
  if allow_screen_content_tools &&
    block.width <= 64 &&
    block.height <= 64 &&
    block.width * block.height >= 64 {
    let context = av1_msac_floor_log2(block.width) +
      av1_msac_floor_log2(block.height) -
      6
    if y_mode == 0 &&
      decoder.symbol(
        state.y_mode[context][av1_palette_mode_context(state, block)],
      ) !=
      0 {
      let size = decoder.symbol(state.y_size[context]) + 2
      state.y_colors = av1_palette_read_base_colors(
        decoder,
        av1_palette_cache(state, block, 0),
        size,
        bit_depth,
        true,
      )
    }
    if has_chroma &&
      uv_mode == 0 &&
      decoder.symbol(
        state.uv_mode[if state.y_colors.length() > 0 { 1 } else { 0 }],
      ) !=
      0 {
      let size = decoder.symbol(state.uv_size[context]) + 2
      state.u_colors = av1_palette_read_base_colors(
        decoder,
        av1_palette_cache(state, block, 1),
        size,
        bit_depth,
        false,
      )
      state.v_colors = av1_palette_read_v_colors(decoder, size, bit_depth)
    }
  }
  av1_palette_record(state, block)
  true
}

// BEGIN GENERATED PALETTE CDFS
// Generated by scripts/generate-av1-palette-tables.py.
// Original AOM 8e7b6a567df174d795479b92b4ac766d271add73, av1/common/entropymode.c:642-783.
// Forward cumulative thresholds include terminal 32768 and update count 0.

///|
fn av1_palette_y_mode_cdfs() -> Array[Array[Array[Int]]] {
  [
    [[31676, 32768, 0], [3419, 32768, 0], [1261, 32768, 0]],
    [[31912, 32768, 0], [2859, 32768, 0], [980, 32768, 0]],
    [[31823, 32768, 0], [3400, 32768, 0], [781, 32768, 0]],
    [[32030, 32768, 0], [3561, 32768, 0], [904, 32768, 0]],
    [[32309, 32768, 0], [7337, 32768, 0], [1462, 32768, 0]],
    [[32265, 32768, 0], [4015, 32768, 0], [1521, 32768, 0]],
    [[32450, 32768, 0], [7946, 32768, 0], [129, 32768, 0]],
  ]
}

///|
fn av1_palette_uv_mode_cdfs() -> Array[Array[Int]] {
  [[32461, 32768, 0], [21488, 32768, 0]]
}

///|
fn av1_palette_y_size_cdfs() -> Array[Array[Int]] {
  [
    [7952, 13000, 18149, 21478, 25527, 29241, 32768, 0],
    [7139, 11421, 16195, 19544, 23666, 28073, 32768, 0],
    [7788, 12741, 17325, 20500, 24315, 28530, 32768, 0],
    [8271, 14064, 18246, 21564, 25071, 28533, 32768, 0],
    [12725, 19180, 21863, 24839, 27535, 30120, 32768, 0],
    [9711, 14888, 16923, 21052, 25661, 27875, 32768, 0],
    [14940, 20797, 21678, 24186, 27033, 28999, 32768, 0],
  ]
}

///|
fn av1_palette_uv_size_cdfs() -> Array[Array[Int]] {
  [
    [8713, 19979, 27128, 29609, 31331, 32272, 32768, 0],
    [5839, 15573, 23581, 26947, 29848, 31700, 32768, 0],
    [4426, 11260, 17999, 21483, 25863, 29430, 32768, 0],
    [3228, 9464, 14993, 18089, 22523, 27420, 32768, 0],
    [3768, 8886, 13091, 17852, 22495, 27207, 32768, 0],
    [2464, 8451, 12861, 21632, 25525, 28555, 32768, 0],
    [1269, 5435, 10433, 18963, 21700, 25865, 32768, 0],
  ]
}

///|
fn av1_palette_y_index_cdfs() -> Array[Array[Array[Int]]] {
  [
    [
      [28710, 32768, 0],
      [16384, 32768, 0],
      [10553, 32768, 0],
      [27036, 32768, 0],
      [31603, 32768, 0],
    ],
    [
      [27877, 30490, 32768, 0],
      [11532, 25697, 32768, 0],
      [6544, 30234, 32768, 0],
      [23018, 28072, 32768, 0],
      [31915, 32385, 32768, 0],
    ],
    [
      [25572, 28046, 30045, 32768, 0],
      [9478, 21590, 27256, 32768, 0],
      [7248, 26837, 29824, 32768, 0],
      [19167, 24486, 28349, 32768, 0],
      [31400, 31825, 32250, 32768, 0],
    ],
    [
      [24779, 26955, 28576, 30282, 32768, 0],
      [8669, 20364, 24073, 28093, 32768, 0],
      [4255, 27565, 29377, 31067, 32768, 0],
      [19864, 23674, 26716, 29530, 32768, 0],
      [31646, 31893, 32147, 32426, 32768, 0],
    ],
    [
      [23132, 25407, 26970, 28435, 30073, 32768, 0],
      [7443, 17242, 20717, 24762, 27982, 32768, 0],
      [6300, 24862, 26944, 28784, 30671, 32768, 0],
      [18916, 22895, 25267, 27435, 29652, 32768, 0],
      [31270, 31550, 31808, 32059, 32353, 32768, 0],
    ],
    [
      [23105, 25199, 26464, 27684, 28931, 30318, 32768, 0],
      [6950, 15447, 18952, 22681, 25567, 28563, 32768, 0],
      [7560, 23474, 25490, 27203, 28921, 30708, 32768, 0],
      [18544, 22373, 24457, 26195, 28119, 30045, 32768, 0],
      [31198, 31451, 31670, 31882, 32123, 32391, 32768, 0],
    ],
    [
      [21689, 23883, 25163, 26352, 27506, 28827, 30195, 32768, 0],
      [6892, 15385, 17840, 21606, 24287, 26753, 29204, 32768, 0],
      [5651, 23182, 25042, 26518, 27982, 29392, 30900, 32768, 0],
      [19349, 22578, 24418, 25994, 27524, 29031, 30448, 32768, 0],
      [31028, 31270, 31504, 31705, 31927, 32153, 32392, 32768, 0],
    ],
  ]
}

///|
fn av1_palette_uv_index_cdfs() -> Array[Array[Array[Int]]] {
  [
    [
      [29089, 32768, 0],
      [16384, 32768, 0],
      [8713, 32768, 0],
      [29257, 32768, 0],
      [31610, 32768, 0],
    ],
    [
      [25257, 29145, 32768, 0],
      [12287, 27293, 32768, 0],
      [7033, 27960, 32768, 0],
      [20145, 25405, 32768, 0],
      [30608, 31639, 32768, 0],
    ],
    [
      [24210, 27175, 29903, 32768, 0],
      [9888, 22386, 27214, 32768, 0],
      [5901, 26053, 29293, 32768, 0],
      [18318, 22152, 28333, 32768, 0],
      [30459, 31136, 31926, 32768, 0],
    ],
    [
      [22980, 25479, 27781, 29986, 32768, 0],
      [8413, 21408, 24859, 28874, 32768, 0],
      [2257, 29449, 30594, 31598, 32768, 0],
      [19189, 21202, 25915, 28620, 32768, 0],
      [31844, 32044, 32281, 32518, 32768, 0],
    ],
    [
      [22217, 24567, 26637, 28683, 30548, 32768, 0],
      [7307, 16406, 19636, 24632, 28424, 32768, 0],
      [4441, 25064, 26879, 28942, 30919, 32768, 0],
      [17210, 20528, 23319, 26750, 29582, 32768, 0],
      [30674, 30953, 31396, 31735, 32207, 32768, 0],
    ],
    [
      [21239, 23168, 25044, 26962, 28705, 30506, 32768, 0],
      [6545, 15012, 18004, 21817, 25503, 28701, 32768, 0],
      [3448, 26295, 27437, 28704, 30126, 31442, 32768, 0],
      [15889, 18323, 21704, 24698, 26976, 29690, 32768, 0],
      [30988, 31204, 31479, 31734, 31983, 32325, 32768, 0],
    ],
    [
      [21442, 23288, 24758, 26246, 27649, 28980, 30563, 32768, 0],
      [5863, 14933, 17552, 20668, 23683, 26411, 29273, 32768, 0],
      [3415, 25810, 26877, 27990, 29223, 30394, 31618, 32768, 0],
      [17965, 20084, 22232, 23974, 26274, 28402, 30390, 32768, 0],
      [31190, 31329, 31516, 31679, 31825, 32026, 32322, 32768, 0],
    ],
  ]
}
// END GENERATED PALETTE CDFS