// cmap:解析 format 4 / format 12,并为子集重建这两张表。
//
// 解析时把编码记录按「覆盖面优先」排序(3/10 → 0/6 → 0/4 → 3/1 → …),
// 先写入的映射不会被后面的表覆盖,因此 format 12 优先于 format 4。

///|
fn cmap_preference(platform : Int, encoding : Int) -> Int {
  if platform == 3 && encoding == 10 {
    0
  } else if platform == 0 && encoding == 6 {
    1
  } else if platform == 0 && encoding == 4 {
    2
  } else if platform == 3 && encoding == 1 {
    3
  } else if platform == 0 && encoding == 3 {
    4
  } else if platform == 0 && encoding == 2 {
    5
  } else if platform == 0 && encoding == 1 {
    6
  } else if platform == 0 && encoding == 0 {
    7
  } else {
    99
  }
}

///|
fn parse_cmap(
  bytes : Bytes,
  record : TableRecord,
) -> (Map[Int, Int], Array[Int]) raise FontError {
  let base = record.offset
  need(bytes, base, 4)
  let count = ru16(bytes, base + 2)
  let records : Array[(Int, Int, Int, Int)] = []
  let mut i = 0
  while i < count {
    let at = base + 4 + i * 8
    need(bytes, at, 8)
    let platform = ru16(bytes, at)
    let encoding = ru16(bytes, at + 2)
    let offset = ru32(bytes, at + 4)
    records.push(
      (cmap_preference(platform, encoding), platform, encoding, offset),
    )
    i = i + 1
  }
  records.sort_by(fn(a, b) { a.0 - b.0 })
  let map : Map[Int, Int] = Map([])
  let formats : Array[Int] = []
  for entry in records {
    if entry.0 < 99 {
      let sub = base + entry.3
      let format = ru16(bytes, sub)
      if format == 4 {
        parse_format4(bytes, sub, map)
        if !formats.contains(4) {
          formats.push(4)
        }
      } else if format == 12 {
        parse_format12(bytes, sub, map)
        if !formats.contains(12) {
          formats.push(12)
        }
      }
    }
  }
  (map, formats)
}

///|
fn parse_format4(
  bytes : Bytes,
  sub : Int,
  map : Map[Int, Int],
) -> Unit raise FontError {
  let seg_count_x2 = ru16(bytes, sub + 6)
  let seg_count = seg_count_x2 / 2
  let end_base = sub + 14
  let start_base = sub + 16 + seg_count_x2
  let delta_base = sub + 16 + seg_count_x2 * 2
  let range_base = sub + 16 + seg_count_x2 * 3
  let mut segment = 0
  let mut steps = 0
  while segment < seg_count && steps < 200000 {
    let end_code = ru16(bytes, end_base + segment * 2)
    let start_code = ru16(bytes, start_base + segment * 2)
    let delta = ru16(bytes, delta_base + segment * 2)
    let range_offset = ru16(bytes, range_base + segment * 2)
    if start_code <= end_code && start_code != 0xFFFF {
      let mut code = start_code
      while code <= end_code && steps < 200000 {
        let mut glyph = 0
        if range_offset == 0 {
          glyph = (code + delta) & 0xFFFF
        } else {
          let glyph_at = range_base +
            segment * 2 +
            range_offset +
            (code - start_code) * 2
          glyph = ru16(bytes, glyph_at)
          if glyph != 0 {
            glyph = (glyph + delta) & 0xFFFF
          }
        }
        if glyph != 0 && !map.contains(code) {
          map.set(code, glyph)
        }
        code = code + 1
        steps = steps + 1
      }
    }
    segment = segment + 1
  }
}

///|
fn parse_format12(
  bytes : Bytes,
  sub : Int,
  map : Map[Int, Int],
) -> Unit raise FontError {
  let groups = ru32(bytes, sub + 12)
  let mut i = 0
  let mut steps = 0
  while i < groups && steps < 400000 {
    let at = sub + 16 + i * 12
    let start_code = ru32(bytes, at)
    let end_code = ru32(bytes, at + 4)
    let start_glyph = ru32(bytes, at + 8)
    if start_code <= end_code && end_code <= 0x10FFFF {
      let mut code = start_code
      while code <= end_code && steps < 400000 {
        let glyph = start_glyph + (code - start_code)
        if glyph != 0 && !map.contains(code) {
          map.set(code, glyph)
        }
        code = code + 1
        steps = steps + 1
      }
    }
    i = i + 1
  }
}

// ---------------------------------------------------------------------------
// 重建
// ---------------------------------------------------------------------------

///|
/// 把有序的 (码点, 字形) 对压缩成连续段:相邻码点且字形也连续时合并。
/// 返回 (start_code, end_code, start_glyph)。
fn build_segments(pairs : Array[(Int, Int)]) -> Array[(Int, Int, Int)] {
  let segments : Array[(Int, Int, Int)] = []
  let mut i = 0
  while i < pairs.length() {
    let start = pairs[i].0
    let glyph = pairs[i].1
    let mut j = i
    let mut contiguous = true
    while contiguous && j + 1 < pairs.length() {
      if pairs[j + 1].0 == pairs[j].0 + 1 && pairs[j + 1].1 == pairs[j].1 + 1 {
        j = j + 1
      } else {
        contiguous = false
      }
    }
    segments.push((start, pairs[j].0, glyph))
    i = j + 1
  }
  segments
}

///|
/// 计算格式 4 头部里的 searchRange / entrySelector / rangeShift。
fn format4_search_fields(seg_count : Int) -> (Int, Int, Int) {
  let mut power = 1
  let mut selector = 0
  while power * 2 <= seg_count {
    power = power * 2
    selector = selector + 1
  }
  let search_range = power * 2
  (search_range, selector, seg_count * 2 - search_range)
}

///|
fn build_format4(pairs : Array[(Int, Int)]) -> Array[Byte] {
  let bmp : Array[(Int, Int)] = []
  for pair in pairs {
    if pair.0 <= 0xFFFF {
      bmp.push(pair)
    }
  }
  let segments = build_segments(bmp)
  let seg_count = segments.length() + 1
  let (search_range, selector, range_shift) = format4_search_fields(seg_count)
  let out : Array[Byte] = []
  push_u16(out, 4)
  push_u16(out, 16 + 8 * seg_count)
  push_u16(out, 0)
  push_u16(out, seg_count * 2)
  push_u16(out, search_range)
  push_u16(out, selector)
  push_u16(out, range_shift)
  for segment in segments {
    push_u16(out, segment.1)
  }
  push_u16(out, 0xFFFF)
  push_u16(out, 0) // reservedPad
  for segment in segments {
    push_u16(out, segment.0)
  }
  push_u16(out, 0xFFFF)
  for segment in segments {
    push_u16(out, (segment.2 - segment.0) & 0xFFFF)
  }
  push_u16(out, 1)
  let mut i = 0
  while i < seg_count {
    push_u16(out, 0)
    i = i + 1
  }
  out
}

///|
fn build_format12(pairs : Array[(Int, Int)]) -> Array[Byte] {
  let segments = build_segments(pairs)
  let out : Array[Byte] = []
  push_u16(out, 12)
  push_u16(out, 0)
  push_u32(out, 16 + 12 * segments.length())
  push_u32(out, 0)
  push_u32(out, segments.length())
  for segment in segments {
    push_u32(out, segment.0)
    push_u32(out, segment.1)
    push_u32(out, segment.2)
  }
  out
}

///|
/// 生成 cmap 表:一组 (3,1) 格式 4,加一组覆盖全平面的 (3,10) 格式 12。
fn build_cmap(pairs : Array[(Int, Int)]) -> Bytes {
  let sub4 = build_format4(pairs)
  let sub12 = build_format12(pairs)
  let header_length = 4 + 8 * 2
  let out : Array[Byte] = []
  push_u16(out, 0)
  push_u16(out, 2)
  push_u16(out, 3)
  push_u16(out, 1)
  push_u32(out, header_length)
  push_u16(out, 3)
  push_u16(out, 10)
  push_u32(out, header_length + sub4.length())
  for value in sub4 {
    out.push(value)
  }
  for value in sub12 {
    out.push(value)
  }
  bytes_of(out)
}