///|
/// Helper to parse an integer from an ASCII string safely.
fn parse_ascii_int(s : String) -> Int? {
  let len = s.length()
  if len == 0 {
    return None
  }
  let mut res = 0
  let mut is_neg = false
  let mut start = 0
  if s[0] == '-' {
    is_neg = true
    start = 1
  } else if s[0] == '+' {
    start = 1
  }
  if start >= len {
    return None
  }
  for i in start..= 48 && c <= 57 {
      res = res * 10 + (c - 48)
    } else {
      return None
    }
  }
  if is_neg {
    Some(-res)
  } else {
    Some(res)
  }
}

///|
/// Exports a 24-bit ColorImage to NetPBM PPM (P3 ASCII format) string.
pub fn ColorImage::to_ppm(self : ColorImage) -> String {
  let buf = StringBuilder()
  buf.write_string("P3\n")
  buf.write_string(self.width.to_string())
  buf.write_string(" ")
  buf.write_string(self.height.to_string())
  buf.write_string("\n255\n")

  for y in 0.. Image? {
  let lines = content.split("\n")
  let tokens : Array[String] = []

  for line in lines {
    let trimmed = line.trim().to_owned()
    // Skip comments
    if !trimmed.has_prefix("#") && trimmed.length() > 0 {
      let parts = trimmed.split(" ")
      for p in parts {
        let pt = p.trim().to_owned()
        if pt.length() > 0 {
          tokens.push(pt)
        }
      }
    }
  }

  if tokens.length() < 4 || tokens[0] != "P2" {
    return None
  }

  let width = match parse_ascii_int(tokens[1]) {
    Some(w) => w
    None => return None
  }
  let height = match parse_ascii_int(tokens[2]) {
    Some(h) => h
    None => return None
  }

  if width <= 0 || height <= 0 {
    return None
  }

  let img = Image::new(width, height)
  let expected_pixels = width * height
  let offset = 4 // After P2, width, height, max_val

  for i in 0.. {
          let x = i % width
          let y = i / width
          img.set(x, y, v)
        }
        None => ()
      }
    }
  }

  Some(img)
}

///|
/// Parses an ASCII PPM (P3) string into a 24-bit ColorImage.
pub fn parse_ppm_ascii(content : String) -> ColorImage? {
  let lines = content.split("\n")
  let tokens : Array[String] = []

  for line in lines {
    let trimmed = line.trim().to_owned()
    if !trimmed.has_prefix("#") && trimmed.length() > 0 {
      let parts = trimmed.split(" ")
      for p in parts {
        let pt = p.trim().to_owned()
        if pt.length() > 0 {
          tokens.push(pt)
        }
      }
    }
  }

  if tokens.length() < 4 || tokens[0] != "P3" {
    return None
  }

  let width = match parse_ascii_int(tokens[1]) {
    Some(w) => w
    None => return None
  }
  let height = match parse_ascii_int(tokens[2]) {
    Some(h) => h
    None => return None
  }

  if width <= 0 || height <= 0 {
    return None
  }

  let img = ColorImage::new(width, height)
  let expected_pixels = width * height
  let offset = 4

  for i in 0.. v
        None => 0
      }
      let g = match parse_ascii_int(tokens[tok_idx + 1]) {
        Some(v) => v
        None => 0
      }
      let b = match parse_ascii_int(tokens[tok_idx + 2]) {
        Some(v) => v
        None => 0
      }
      let x = i % width
      let y = i / width
      img.set(x, y, ColorRGB::new(r, g, b))
    }
  }

  Some(img)
}