// id3_text.mbt
//
// ID3v2 的文本编码处理。
//
// 编码字节(帧载荷第一个字节):
//   $00 ISO-8859-1,$00 终止
//   $01 UTF-16(带 BOM),$00 00 终止
//   $02 UTF-16BE(无 BOM),$00 00 终止
//   $03 UTF-8,$00 终止
//
// 规范允许一个文本帧内含多个以终止符分隔的字符串(v2.4 的多值语义),
// 所以这里提供"按编码切分字符串"的统一入口,而不是只解第一段。

///|
/// 文本编码枚举。
pub enum TextEncoding {
  /// `$00` ISO-8859-1
  Latin1
  /// `$01` UTF-16 with BOM
  Utf16Bom
  /// `$02` UTF-16BE without BOM
  Utf16Be
  /// `$03` UTF-8
  Utf8
}

///|
/// 把编码字节转成枚举;未知编码抛错。
pub fn TextEncoding::from_code(code : Int32) -> TextEncoding raise TagError {
  match code {
    0 => Latin1
    1 => Utf16Bom
    2 => Utf16Be
    3 => Utf8
    _ =>
      raise BadFrameData(
        frame_id="",
        reason="未知的文本编码字节 \{code}",
      )
  }
}

///|
/// 编码字节(写入用)。
pub fn TextEncoding::code(self : TextEncoding) -> Int32 {
  match self {
    Latin1 => 0
    Utf16Bom => 1
    Utf16Be => 2
    Utf8 => 3
  }
}

///|
/// 该编码的终止符长度:Latin1/UTF-8 为 1 字节,两种 UTF-16 为 2 字节。
pub fn TextEncoding::terminator_len(self : TextEncoding) -> Int32 {
  match self {
    Latin1 | Utf8 => 1
    Utf16Bom | Utf16Be => 2
  }
}

///|
/// 解码单个字符串(不含终止符)。非法序列按替换字符处理,不抛错——
/// 标签里存在历史遗留的坏字节是常态,读取侧应尽量给出可显示结果。
pub fn TextEncoding::decode(self : TextEncoding, bytes : BytesView) -> String {
  match self {
    Latin1 => latin1_decode(bytes)
    Utf8 => @utf8.decode_lossy(bytes)
    Utf16Be => @utf16.decode_lossy(bytes, ignore_bom=true, endianness=Big)
    Utf16Bom =>
      // BOM 决定字节序;缺失时按小端处理(历史实现的实际做法)。
      if bytes.length() >= 2 && bytes.at(0) == b'\xFF' && bytes.at(1) == b'\xFE' {
        @utf16.decode_lossy(bytes, ignore_bom=true, endianness=Little)
      } else if bytes.length() >= 2 &&
        bytes.at(0) == b'\xFE' &&
        bytes.at(1) == b'\xFF' {
        @utf16.decode_lossy(bytes, ignore_bom=true, endianness=Big)
      } else {
        @utf16.decode_lossy(bytes, ignore_bom=false, endianness=Little)
      }
  }
}

///|
/// ISO-8859-1 → Unicode:逐字节取码点,无需查表。
fn latin1_decode(bytes : BytesView) -> String {
  let buf = StringBuilder()
  for i in 0.. Int32 {
  match encoding {
    Latin1 | Utf8 => {
      let mut i = start
      while i < end {
        if data.at(i) == b'\x00' {
          return i
        }
        i += 1
      }
      end
    }
    Utf16Bom | Utf16Be => {
      let mut i = start
      while i + 1 < end {
        if data.at(i) == b'\x00' && data.at(i + 1) == b'\x00' {
          return i
        }
        i += 2
      }
      end
    }
  }
}

///|
/// 按编码把一段载荷切分为多个字符串。
///
/// 末尾的空串(终止符之后的尾随填充)会被丢弃。返回值保留原始顺序。
pub fn split_strings(
  data : BytesView,
  encoding : TextEncoding,
  start : Int32,
  end : Int32,
) -> Array[String] {
  let out : Array[String] = []
  let term = encoding.terminator_len()
  let mut pos = start
  while pos < end {
    let stop = find_terminator(data, pos, encoding, end)
    // 全零剩余视为填充,不再产出空串
    let text = encoding.decode(data.exact_view(start=pos, end=stop))
    out.push(text)
    pos = stop + term
    if stop >= end {
      break
    }
  }
  // 去掉尾部空字符串(终止符后的填充区)
  while out.length() > 0 && out[out.length() - 1] == "" {
    let _ = out.pop()
  }
  out
}