// SFNT 字节层:大端读写、边界检查与校验和。
//
// 约定:
//   - 所有多字节整数按大端读取;
//   - 所有读取先做边界检查,任意输入都只会得到 FontError,不会越界;
//   - 校验和按 OpenType 规范以 32 位无符号累加,不足 4 字节的部分补 0。

///|
pub suberror FontError {
  FontTruncated
  FontNotSfnt
  FontUnsupported(String)
  FontMissingTable(String)
  FontBadTable(String)
  FontIo(String)
}

///|
pub fn font_error_message(error : FontError) -> String {
  match error {
    FontTruncated => "文件被截断:所需字节超出数据长度"
    FontNotSfnt =>
      "不是 TrueType/OpenType 字体(sfnt 版本号不匹配)"
    FontUnsupported(what) => "暂不支持:\{what}"
    FontMissingTable(tag) => "缺少必需表:\{tag}"
    FontBadTable(tag) => "表结构非法:\{tag}"
    FontIo(path) => "读取字体失败:\{path}"
  }
}

///|
fn need(bytes : Bytes, off : Int, len : Int) -> Unit raise FontError {
  if off < 0 || len < 0 || off + len > bytes.length() {
    raise FontTruncated
  }
}

///|
fn ru16(bytes : Bytes, off : Int) -> Int raise FontError {
  need(bytes, off, 2)
  (bytes.at(off).to_int() << 8) | bytes.at(off + 1).to_int()
}

///|
fn ri16(bytes : Bytes, off : Int) -> Int raise FontError {
  let value = ru16(bytes, off)
  if value >= 0x8000 {
    value - 0x10000
  } else {
    value
  }
}

///|
fn ru32(bytes : Bytes, off : Int) -> Int raise FontError {
  need(bytes, off, 4)
  (ru16(bytes, off) << 16) | ru16(bytes, off + 2)
}

///|
fn ru32u(bytes : Bytes, off : Int) -> UInt raise FontError {
  (ru16(bytes, off).reinterpret_as_uint() << 16) |
  ru16(bytes, off + 2).reinterpret_as_uint()
}

///|
fn tag_at(bytes : Bytes, off : Int) -> String raise FontError {
  need(bytes, off, 4)
  let mut tag = ""
  let mut i = 0
  while i < 4 {
    tag = tag + Int::unsafe_to_char(bytes.at(off + i).to_int()).to_string()
    i = i + 1
  }
  tag
}

// ---------------------------------------------------------------------------
// 写入
// ---------------------------------------------------------------------------

///|
fn push_u8(out : Array[Byte], value : Int) -> Unit {
  out.push((value & 0xFF).to_byte())
}

///|
fn push_u16(out : Array[Byte], value : Int) -> Unit {
  push_u8(out, value >> 8)
  push_u8(out, value)
}

///|
fn push_u32(out : Array[Byte], value : Int) -> Unit {
  push_u16(out, value >> 16)
  push_u16(out, value & 0xFFFF)
}

///|
fn write_u32u_at(out : Array[Byte], at : Int, value : UInt) -> Unit {
  let mask : UInt = 0xFF
  out[at] = ((value >> 24) & mask).to_byte()
  out[at + 1] = ((value >> 16) & mask).to_byte()
  out[at + 2] = ((value >> 8) & mask).to_byte()
  out[at + 3] = (value & mask).to_byte()
}

///|
fn push_zeros(out : Array[Byte], count : Int) -> Unit {
  let mut i = 0
  while i < count {
    out.push(Byte::default())
    i = i + 1
  }
}

///|
fn push_range(
  out : Array[Byte],
  bytes : Bytes,
  start : Int,
  length : Int,
) -> Unit raise FontError {
  need(bytes, start, length)
  let mut i = 0
  while i < length {
    out.push(bytes.at(start + i))
    i = i + 1
  }
}

///|
fn push_tag(out : Array[Byte], tag : String) -> Unit {
  let mut written = 0
  for ch in tag {
    if written < 4 {
      out.push(ch.to_int().to_byte())
      written = written + 1
    }
  }
  while written < 4 {
    out.push(Int::to_byte(0x20))
    written = written + 1
  }
}

///|
fn pad4(length : Int) -> Int {
  (length + 3) / 4 * 4
}

///|
fn bytes_of(out : Array[Byte]) -> Bytes {
  Bytes::from_iter(out.iter())
}

// ---------------------------------------------------------------------------
// 校验和
// ---------------------------------------------------------------------------

///|
fn checksum_range(bytes : Bytes, start : Int, length : Int) -> UInt {
  let mut sum : UInt64 = 0UL
  let mut i = 0
  while i < length {
    let mut word : UInt64 = 0UL
    let mut k = 0
    while k < 4 {
      let index = i + k
      let value = if index < length {
        bytes.at(start + index).to_int()
      } else {
        0
      }
      word = (word << 8) | value.to_uint64()
      k = k + 1
    }
    sum = sum + word
    i = i + 4
  }
  (sum & 0xFFFFFFFFUL).to_uint()
}