///|
pub fn lower_ascii(input : String) -> String {
  let mut out = ""
  for ch in input {
    if ch >= 'A' && ch <= 'Z' {
      out = out + Int::unsafe_to_char(ch.to_int() + 32).to_string()
    } else {
      out = out + ch.to_string()
    }
  }
  out
}

///|
pub fn trim_ascii(input : String) -> String {
  let chars : Array[Char] = []
  for ch in input {
    chars.push(ch)
  }
  let mut start = 0
  let mut end = chars.length()
  while start < end && is_space(chars[start]) {
    start = start + 1
  }
  while end > start && is_space(chars[end - 1]) {
    end = end - 1
  }
  let mut out = ""
  let mut i = start
  while i < end {
    out = out + chars[i].to_string()
    i = i + 1
  }
  out
}

///|
pub fn is_space(ch : Char) -> Bool {
  ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'
}

///|
pub fn is_header_continuation(line : String) -> Bool {
  line.length() > 0 && (line[0] == ' ' || line[0] == '\t')
}

///|
pub fn split_lines(input : String) -> Array[String] {
  let lines : Array[String] = []
  let mut current = ""
  for ch in input {
    if ch == '\n' {
      lines.push(strip_cr(current))
      current = ""
    } else {
      current = current + ch.to_string()
    }
  }
  lines.push(strip_cr(current))
  lines
}

///|
pub fn strip_cr(input : String) -> String {
  if input.length() > 0 && input[input.length() - 1] == '\r' {
    slice(input, 0, input.length() - 1)
  } else {
    input
  }
}

///|
pub fn slice(input : String, start : Int, end : Int) -> String {
  let mut out = ""
  let mut i = 0
  for ch in input {
    if i >= start && i < end {
      out = out + ch.to_string()
    }
    i = i + 1
  }
  out
}

///|
pub fn index_of(input : String, needle : Char) -> Int {
  let mut i = 0
  for ch in input {
    if ch == needle {
      return i
    }
    i = i + 1
  }
  -1
}

///|
pub fn starts_with(input : String, prefix : String) -> Bool {
  if prefix.length() > input.length() {
    false
  } else {
    slice(input, 0, prefix.length()) == prefix
  }
}

///|
pub fn remove_quotes(input : String) -> String {
  let text = trim_ascii(input)
  if text.length() >= 2 && text[0] == '"' && text[text.length() - 1] == '"' {
    slice(text, 1, text.length() - 1)
  } else {
    text
  }
}

///|
pub fn split_once(input : String, sep : Char) -> (String, String)? {
  let idx = index_of(input, sep)
  if idx < 0 {
    None
  } else {
    Some((slice(input, 0, idx), slice(input, idx + 1, input.length())))
  }
}

///|
pub fn split_char(input : String, sep : Char) -> Array[String] {
  let out : Array[String] = []
  let mut current = ""
  for ch in input {
    if ch == sep {
      out.push(current)
      current = ""
    } else {
      current = current + ch.to_string()
    }
  }
  out.push(current)
  out
}