///|
/// Computes bitwise Hamming distance between two 64-bit integers (popcount of XOR).
pub fn compute_hamming_distance(val1 : Int64, val2 : Int64) -> Int {
  let mut x = val1 ^ val2
  let mut count = 0
  while x != 0L {
    count += (x & 1L).to_int()
    x = x >> 1
  }
  count
}

///|
/// Rotates an N x N binary bit grid 90 degrees clockwise (standard raster order).
pub fn rotate_bits_90(bits : Int64, grid_size : Int) -> Int64 {
  let mut rotated = 0L
  for r in 0..> orig_idx) & 1L
      if bit_val == 1L {
        let new_r = c
        let new_c = grid_size - 1 - r
        let new_idx = new_r * grid_size + new_c
        rotated = rotated | (1L << new_idx)
      }
    }
  }
  rotated
}

///|
/// Rotates AprilTag 16h5 16-bit payload according to official AprilTag spiral coordinate layout.
pub fn rotate_apriltag_16h5_bits(bits : Int64) -> Int64 {
  let rot_map = [12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
  let mut res = 0L
  for i in 0..<16 {
    let bit_val = (bits >> i) & 1L
    if bit_val == 1L {
      let new_idx = rot_map[i]
      res = res | (1L << new_idx)
    }
  }
  res
}

///|
/// Finds the best codeword match in dictionary across all 4 90-degree rotations.
pub fn MarkerDictionary::find_best_match(
  self : MarkerDictionary,
  candidate_bits : Int64,
) -> (Int, Int, Int)? {
  let mut best_id = -1
  let mut best_rot = 0
  let mut min_dist = self.max_correction_bits + 1

  let mut curr_bits = candidate_bits

  for rot in 0..<4 {
    for i in 0..= 0 {
    Some((best_id, best_rot, min_dist))
  } else {
    None
  }
}

///|
/// Official OpenCV ArUco DICT_4X4_50 dictionary definition (50 canonical codewords).
/// Minimum inter-codeword Hamming distance across all 4 rotations is EXACTLY 4.
/// Max correction bits = 1.
pub fn dictionary_aruco_4x4_50() -> MarkerDictionary {
  let codewords = [
    0xb532L, 0x0f9aL, 0x332dL, 0x9946L, 0x549eL, 0x79cdL, 0x9e2eL, 0xc4f2L, 0xfedaL,
    0xcf56L, 0xf991L, 0x11a7L, 0x0eb7L, 0x2a0fL, 0x24b1L, 0x263eL, 0x4665L, 0x6600L,
    0x6c5eL, 0x76afL, 0x868bL, 0xb02bL, 0xccd5L, 0xdd82L, 0xfe47L, 0x9471L, 0xace4L,
    0xa554L, 0x2123L, 0x346fL, 0x4415L, 0x57b2L, 0x9ecfL, 0xf0cbL, 0x08aeL, 0x0929L,
    0x1875L, 0x04ffL, 0x0df6L, 0x1c5aL, 0x1718L, 0x2a28L, 0x328cL, 0x38b2L, 0x24e8L,
    0x2eebL, 0x2d3fL, 0x4b64L, 0x502eL, 0x5013L,
  ]
  {
    name: "ArUco_4x4_50",
    grid_size: 4,
    payload_bits: 16,
    max_correction_bits: 1,
    codewords,
  }
}

///|
/// Official AprilTag 16h5 (tag16h5) dictionary definition (30 canonical codewords).
/// Minimum inter-codeword Hamming distance across all 4 rotations is EXACTLY 5 (h5).
/// Max correction bits = 2.
pub fn dictionary_apriltag_16h5() -> MarkerDictionary {
  let codewords = [
    0x27c8L, 0x31b6L, 0x3859L, 0x569cL, 0x6c76L, 0x7ddbL, 0xaf09L, 0xf5a1L, 0xfb8bL,
    0x1cb9L, 0x28caL, 0xe8dcL, 0x1426L, 0x5770L, 0x9253L, 0xb702L, 0x063aL, 0x8f34L,
    0xb4c0L, 0x51ecL, 0xe6f0L, 0x5fa4L, 0xdd43L, 0x1aaaL, 0xe62fL, 0x6dbcL, 0xb6ebL,
    0xde10L, 0x154dL, 0xb57aL,
  ]
  {
    name: "AprilTag_16h5",
    grid_size: 4,
    payload_bits: 16,
    max_correction_bits: 2,
    codewords,
  }
}

///|
/// Official AprilTag 36h11 (tag36h11) dictionary definition (first 30 canonical 36-bit codewords).
/// Minimum inter-codeword Hamming distance across all 4 rotations is EXACTLY 11 (h11).
/// Max correction bits = 5.
pub fn dictionary_apriltag_36h11() -> MarkerDictionary {
  let codewords = [
    0xd7e00984bL, 0xdda664ca7L, 0xdc4a1c821L, 0xe17b470e9L, 0xef91d01b1L, 0xf429cdd73L,
    0x05da29225L, 0x1106cba43L, 0x223bed79dL, 0x21f51213cL, 0x367f08c35L, 0x3b11efab9L,
    0x3d0b284e9L, 0x47781b297L, 0x498e8210dL, 0x5463f6831L, 0x5a1f4eb27L, 0x629528d95L,
    0x64cf510b9L, 0x6ccfa4445L, 0x6fb28c50fL, 0x76395b05fL, 0x794b6ca53L, 0x79c8dc191L,
    0x8291410bdL, 0x8a9235e1bL, 0x8b375b4dbL, 0x904a43b19L, 0x96f6e5223L, 0x9780cb429L,
  ]
  {
    name: "AprilTag_36h11",
    grid_size: 6,
    payload_bits: 36,
    max_correction_bits: 5,
    codewords,
  }
}