///|
/// Code 93 内部字符集(0-42 为基本字符,43-46 为扩展移位符 a($)/b(%)/c(/)/d(+),
/// 47 为起始/终止符 `*`)。下标即 mod-47 校验值。
let code93_charset : String = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd*"

///|
/// Code 93 基本字符集(不含移位符与起始/终止符),用于非 Full-ASCII 模式。
let code93_basic_charset : String = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%"

///|
/// Code 93 的 48 个 9 模块模式(1=条,0=空),索引与字符集一致。
let code93_patterns : Array[String] = [
  "100010100", // 0
   "101001000", // 1
   "101000100", // 2
   "101000010", // 3
   "100101000", // 4
   "100100100", // 5
   "100100010", // 6
   "101010000", // 7
   "100010010", // 8
   "100001010", // 9
   "110101000", // A
   "110100100", // B
   "110100010", // C
   "110010100", // D
   "110010010", // E
   "110001010", // F
   "101101000", // G
   "101100100", // H
   "101100010", // I
   "100110100", // J
   "100011010", // K
   "101011000", // L
   "101001100", // M
   "101000110", // N
   "100101100", // O
   "100010110", // P
   "110110100", // Q
   "110110010", // R
   "110101100", // S
   "110100110", // T
   "110010110", // U
   "110011010", // V
   "101101100", // W
   "101100110", // X
   "100110110", // Y
   "100111010", // Z
   "100101110", // -
   "111010100", // .
   "111010010", // space
   "111001010", // $
   "101101110", // /
   "101110110", // +
   "110101110", // %
   "100100110", // ($)
   "111011010", // (%)
   "111010110", // (/)
   "100110010", // (+)
   "101011110", // *
]

///|
/// 返回字符在 Code 93 内部字符集中的下标。
fn code93_value(c : Byte) -> Int? {
  let cs = @utf8.encode(code93_charset)
  for i = 0; i < cs.length(); i = i + 1 {
    if cs[i] == c {
      return Some(i)
    }
  }
  None
}

///|
/// 判断字节是否属于 Code 93 基本字符集。
fn code93_basic_ok(c : Byte) -> Bool {
  let cs = @utf8.encode(code93_basic_charset)
  for i = 0; i < cs.length(); i = i + 1 {
    if cs[i] == c {
      return true
    }
  }
  false
}

///|
/// 追加一个 ASCII 码对应的字节。
fn append_ascii(out : Buffer, code : Int) -> Unit {
  out.write_byte(code.to_byte())
}

///|
/// 按 Full-ASCII 规则将一个字节转换为内部字符序列(1-2 字节),
/// 写入 `out`;不可编码时返回 false。
fn code93_extend_char(c : Byte, out : Buffer) -> Bool {
  let n = c.to_int()
  if n == 0 {
    // NUL -> (%)U
    out.write_string_utf8("bU")
    return true
  }
  if n <= 26 {
    // SOH-SUB -> ($)A-($)Z
    out.write_byte(b'a')
    append_ascii(out, 65 + (n - 1))
    return true
  }
  if n <= 31 {
    // ESC-US -> (%)A-(%)E
    out.write_byte(b'b')
    append_ascii(out, 65 + (n - 27))
    return true
  }
  if c == b' ' || c == b'$' || c == b'%' || c == b'+' {
    out.write_byte(c)
    return true
  }
  if n <= 44 {
    // !"#&'()*, -> (/)A-(/)L
    out.write_byte(b'c')
    append_ascii(out, 65 + (n - 33))
    return true
  }
  if n <= 57 {
    // - . / 0-9 直接编码
    out.write_byte(c)
    return true
  }
  if c == b':' {
    out.write_string_utf8("cZ")
    return true
  }
  if n <= 63 {
    // ;<=>? -> (%)F-(%)J
    out.write_byte(b'b')
    append_ascii(out, 70 + (n - 59))
    return true
  }
  if c == b'@' {
    out.write_string_utf8("bV")
    return true
  }
  if n <= 90 {
    // A-Z 直接编码
    out.write_byte(c)
    return true
  }
  if n <= 95 {
    // [\]^_ -> (%)K-(%)O
    out.write_byte(b'b')
    append_ascii(out, 75 + (n - 91))
    return true
  }
  if c == b'`' {
    out.write_string_utf8("bW")
    return true
  }
  if n <= 122 {
    // a-z -> (+)A-(+)Z
    out.write_byte(b'd')
    append_ascii(out, 65 + (n - 97))
    return true
  }
  if n <= 127 {
    // {|}~DEL -> (%)P-(%)T
    out.write_byte(b'b')
    append_ascii(out, 80 + (n - 123))
    return true
  }
  false
}

///|
/// 将输入转换为 Code 93 内部字符序列(Buffer of bytes)。
fn code93_to_internal(
  data : String,
  full_ascii : Bool,
) -> Result[Bytes, String] {
  let b = @utf8.encode(data)
  if b.length() == 0 {
    return Err("Code 93 data must not be empty")
  }
  let out = Buffer()
  if full_ascii {
    for i = 0; i < b.length(); i = i + 1 {
      if !code93_extend_char(b[i], out) {
        return Err("Code 93 data contains a non-encodable character")
      }
    }
  } else {
    for i = 0; i < b.length(); i = i + 1 {
      if !code93_basic_ok(b[i]) {
        return Err("Code 93 basic mode rejects this character")
      }
      out.write_byte(b[i])
    }
  }
  Ok(out.to_bytes())
}

///|
/// 将内部字符序列转为值数组。
fn code93_values(chars : Bytes) -> Result[Array[Int], String] {
  let out : Array[Int] = []
  for i = 0; i < chars.length(); i = i + 1 {
    match code93_value(chars[i]) {
      None => return Err("Code 93 data contains a non-encodable character")
      Some(v) => out.push(v)
    }
  }
  Ok(out)
}

///|
/// mod-47 校验和:最右侧权重 1,向左递增,超过 `max_weight` 后重置为 1。
fn code93_checksum(values : Array[Int], max_weight : Int) -> Int {
  let mut total = 0
  let mut weight = 1
  let mut i = values.length() - 1
  while i >= 0 {
    total = total + values[i] * weight
    weight = weight + 1
    if weight > max_weight {
      weight = 1
    }
    i = i - 1
  }
  total % 47
}

///|
/// 计算 Code 93 的 C 与 K 两个 mod-47 校验值。
///
/// 权重从最右侧字符为 1 向左递增;C 的最大权重为 20,K 的最大权重为 15
/// 且计算时包含 C。
pub fn code93_checksums(
  data : String,
  full_ascii? : Bool = true,
) -> Result[(Int, Int), String] {
  match code93_to_internal(data, full_ascii) {
    Err(msg) => Err(msg)
    Ok(bytes) =>
      match code93_values(bytes) {
        Err(msg) => Err(msg)
        Ok(vs) => {
          let c = code93_checksum(vs, 20)
          let with_c : Array[Int] = []
          for v in vs {
            with_c.push(v)
          }
          with_c.push(c)
          let k = code93_checksum(with_c, 15)
          Ok((c, k))
        }
      }
  }
}

///|
/// 编码 Code 93。
///
/// `full_ascii` 为 true(默认)时支持全部 128 个 ASCII 字符(小写、标点、
/// 控制字符经移位符扩展);为 false 时仅支持 43 个基本字符。
/// 输出结构:起始 `*` + 数据 + C + K + 终止 `*` + 终止条。
pub fn encode_code93(
  data : String,
  full_ascii? : Bool = true,
) -> Result[Barcode, EncodeError] {
  match code93_to_internal(data, full_ascii) {
    Err(msg) => Err(InvalidData(msg))
    Ok(bytes) =>
      match code93_values(bytes) {
        Err(msg) => Err(InvalidData(msg))
        Ok(vs) => {
          let c = code93_checksum(vs, 20)
          let with_c : Array[Int] = []
          for v in vs {
            with_c.push(v)
          }
          with_c.push(c)
          let k = code93_checksum(with_c, 15)
          let modules : Array[Bool] = []
          append_code93_pattern(modules, code93_patterns[47])
          for v in vs {
            append_code93_pattern(modules, code93_patterns[v])
          }
          append_code93_pattern(modules, code93_patterns[c])
          append_code93_pattern(modules, code93_patterns[k])
          append_code93_pattern(modules, code93_patterns[47])
          modules.push(true) // 终止条
          Ok({ symbology: Code93, data, modules })
        }
      }
  }
}

///|
/// 追加一个 Code 93 字符的 9 模块模式。
fn append_code93_pattern(modules : Array[Bool], pattern : String) -> Unit {
  let p = @utf8.encode(pattern)
  for i = 0; i < p.length(); i = i + 1 {
    modules.push(p[i] == b'1')
  }
}

///|
/// 校验 Code 93 数据是否可编码。
pub fn validate_code93(
  data : String,
  full_ascii? : Bool = true,
) -> Result[Unit, EncodeError] {
  match encode_code93(data, full_ascii~) {
    Err(e) => Err(e)
    Ok(_) => Ok(())
  }
}