/*
 * This file is part of the Fun programming language.
 * https://fun-lang.xyz/
 *
 * Copyright 2025 Johannes Findeisen
 * Licensed under the terms of the Apache-2.0 license.
 * https://opensource.org/license/apache-2-0
 *
 * Added: 2025-10-01
 */

// Extra string utilities

// Trim whitespace on the left (space, tab, CR, LF)
fun str_ltrim(s)
  src = to_string(s)
  number i = 0
  ws = " \t\r\n"
  while (i < len(src))
    ch = substr(src, i, 1)
    if (find(ws, ch) < 0)
      break
    i = i + 1
  return substr(src, i, len(src) - i)

// Trim whitespace on the right
fun str_rtrim(s)
  src = to_string(s)
  number i = len(src) - 1
  ws = " \t\r\n"
  while (i >= 0)
    ch = substr(src, i, 1)
    if (find(ws, ch) < 0)
      break
    i = i - 1
  return substr(src, 0, i + 1)

// Trim both sides
fun str_trim(s)
  return str_rtrim(str_ltrim(s))

// Return 1 if s starts with prefix, else 0
fun str_starts_with(s, prefix)
  a = to_string(s)
  p = to_string(prefix)
  if (len(p) > len(a))
    return 0
  return substr(a, 0, len(p)) == p

// Return 1 if s ends with suffix, else 0
fun str_ends_with(s, suffix)
  a = to_string(s)
  p = to_string(suffix)
  number la = len(a)
  number lp = len(p)
  if (lp > la)
    return 0
  return substr(a, la - lp, lp) == p

// Split by a single-character delimiter, returns array of strings
fun str_split(s, delim)
  src = to_string(s)
  d = to_string(delim)
  // Use only the first character of delim
  if (len(d) == 0)
    return [src]
  dd = substr(d, 0, 1)
  parts = []
  buf = []
  number i = 0
  number n = len(src)
  while (i < n)
    ch = substr(src, i, 1)
    if (ch == dd)
      push(parts, join(buf, ""))
      buf = []
    else
      push(buf, ch)
    i = i + 1
  // tail
  push(parts, join(buf, ""))
  return parts

// Replace all occurrences of 'from' with 'to' (naive scan)
fun str_replace_all(s, from, to)
  src = to_string(s)
  f = to_string(from)
  t = to_string(to)
  number n = len(src)
  number lf = len(f)
  if (lf == 0)
    return src
  out = []
  number i = 0
  while (i < n)
    if ((i + lf <= n) && (substr(src, i, lf) == f))
      push(out, t)
      i = i + lf
    else
      push(out, substr(src, i, 1))
      i = i + 1
  return join(out, "")

// Lowercase transform for ASCII A..Z
fun str_to_lower(s)
  src = to_string(s)
  U = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  L = "abcdefghijklmnopqrstuvwxyz"
  out = []
  number i = 0
  number n = len(src)
  while (i < n)
    ch = substr(src, i, 1)
    idx = find(U, ch)
    if (idx >= 0)
      push(out, substr(L, idx, 1))
    else
      push(out, ch)
    i = i + 1
  return join(out, "")

// Uppercase transform for ASCII a..z
fun str_to_upper(s)
  src = to_string(s)
  U = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  L = "abcdefghijklmnopqrstuvwxyz"
  out = []
  number i = 0
  number n = len(src)
  while (i < n)
    ch = substr(src, i, 1)
    idx = find(L, ch)
    if (idx >= 0)
      push(out, substr(U, idx, 1))
    else
      push(out, ch)
    i = i + 1
  return join(out, "")

// Repeat string s 'count' times
fun str_repeat(s, count)
  src = to_string(s)
  number c = count
  if (c <= 0)
    return ""
  parts = []
  number i = 0
  while (i < c)
    push(parts, src)
    i = i + 1
  return join(parts, "")

// ASCII string to array of byte codes (0..255)
// For printable ASCII (0x20..0x7E) returns the exact code; for any other
// character it returns 0 as a fallback. This mirrors legacy helpers used by
// crypto libs that expect ASCII input.
fun string_to_bytes_ascii(s)
  str = to_string(s)
  out = []
  number i = 0
  // ASCII printable ranges buckets for quick lookup
  P1 = " !\"#$%&'()*+,-./"          // 32..47
  P2 = "0123456789"                 // 48..57
  P3 = ":;<=>?@"                    // 58..64
  P4 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" // 65..90
  P5 = "[\\]^_`"                    // 91..96
  P6 = "abcdefghijklmnopqrstuvwxyz" // 97..122
  P7 = "{|}~"                       // 123..126
  while (true)
    ch = substr(str, i, 1)
    if (typeof(ch) != "String" || ch == "")
      break
    number code = -1
    idx = find(P1, ch)
    if (idx >= 0)
      code = 32 + idx
    else
      idx = find(P2, ch)
      if (idx >= 0)
        code = 48 + idx
      else
        idx = find(P3, ch)
        if (idx >= 0)
          code = 58 + idx
        else
          idx = find(P4, ch)
          if (idx >= 0)
            code = 65 + idx
          else
            idx = find(P5, ch)
            if (idx >= 0)
              code = 91 + idx
            else
              idx = find(P6, ch)
              if (idx >= 0)
                code = 97 + idx
              else
                idx = find(P7, ch)
                if (idx >= 0)
                  code = 123 + idx
                else
                  // non-printable -> 0
                  code = 0
    push(out, code)
    i = i + 1
  return out
