///|
/// Parse a Unix path string into UnixPath
/// Format: "/path/to/file.ext" or "/path/to/"
pub fn UnixPath::parse(s : StringView) -> UnixPath raise {
  // Handle root path "/"
  if s == "/" {
    return UnixPath::from(directory=Directory([]))
  }

  // Remove leading slash if present
  let path_part = if s.has_prefix("/") {
    s[1:].to_string()
  } else {
    s.to_string() // Relative path
  }

  // Split by forward slash
  let parts = if path_part.is_empty() { [] } else { split_path(path_part, '/') }

  // Determine if last part is a file
  let (dir_parts, file_opt) = if parts.is_empty() {
    ([], None)
  } else {
    let last_part = parts[parts.length() - 1]
    if has_file_extension(last_part) || is_likely_filename(last_part) {
      // Last part is likely a file
      let dir_parts_array = Array::new()
      for i = 0; i < parts.length() - 1; i = i + 1 {
        dir_parts_array.push(parts[i])
      }
      let (base, ext) = split_filename(last_part)
      let file = File::{ base: UnixPathComponent::from(base), extension: ext }
      (dir_parts_array, Some(file))
    } else {
      // All parts are directories
      (parts, None)
    }
  }

  // Create directory components
  let dir_components = dir_parts.map(UnixPathComponent::from)
  let directory = Directory(FixedArray::from_array(dir_components))
  match file_opt {
    Some(file) => UnixPath::from(directory~, file~)
    None => UnixPath::from(directory~)
  }
}

///|
pub fn UnixPath::from(directory~ : UnixDirectory, file? : UnixFile) -> UnixPath {
  UnixPath::{ directory, file }
}

///|
pub impl Show for UnixPath with output(self, logger) {
  // Format: /path/to/file.ext or /path/to/ (if no file)
  logger.write_char('/')

  // Write directory components separated by forward slashes
  for i = 0; i < self.directory.length(); i = i + 1 {
    if i > 0 {
      logger.write_char('/')
    }
    self.directory[i].output(logger)
  }

  // Add file if present
  match self.file {
    Some(file) => {
      if self.directory.length() > 0 {
        logger.write_char('/')
      }
      file.base.output(logger)
      if file.extension.length() > 0 {
        logger.write_char('.')
        logger.write_string(file.extension)
      }
    }
    None => ()
  }
}

///|
test "UnixPath Show implementation" {
  // Test empty directory (root)
  let empty_dir = Directory([])
  let path1 = UnixPath::from(directory=empty_dir)
  inspect(path1.to_string(), content="/")

  // Test with directory components
  let dir_components = ["home", "john", "documents"].map(fn(s) {
    UnixPathComponent(s)
  })
  let dir = Directory(FixedArray::from_array(dir_components))
  let path2 = UnixPath::from(directory=dir)
  inspect(path2.to_string(), content="/home/john/documents")

  // Test with file (no extension)
  let file_base = UnixPathComponent("readme")
  let file = File::{ base: file_base, extension: "" }
  let path3 = UnixPath::from(directory=dir, file~)
  inspect(path3.to_string(), content="/home/john/documents/readme")

  // Test with file and extension
  let file_with_ext = File::{ base: file_base, extension: "txt" }
  let path4 = UnixPath::from(directory=dir, file=file_with_ext)
  inspect(path4.to_string(), content="/home/john/documents/readme.txt")

  // Test file in root directory
  let path5 = UnixPath::from(directory=empty_dir, file=file_with_ext)
  inspect(path5.to_string(), content="/readme.txt")
}

///|
test "UnixPath::parse functionality" {
  // Test root path
  let path1 = UnixPath::parse("/")
  inspect(path1.directory.length(), content="0")
  inspect(path1.file, content="None")

  // Test Unix path with directory
  let path2 = UnixPath::parse("/home/user/documents")
  inspect(path2.directory.length(), content="3")
  inspect(path2.directory[0].0, content="home")
  inspect(path2.directory[1].0, content="user")
  inspect(path2.directory[2].0, content="documents")
  inspect(path2.file, content="None")

  // Test Unix path with file
  let path3 = UnixPath::parse("/etc/config/settings.conf")
  inspect(path3.directory.length(), content="2")
  inspect(path3.directory[0].0, content="etc")
  inspect(path3.directory[1].0, content="config")
  match path3.file {
    Some(file) => {
      inspect(file.base.0, content="settings")
      inspect(file.extension, content="conf")
    }
    None => fail("Expected file")
  }

  // Test Unix path with file at root
  let path4 = UnixPath::parse("/README.md")
  inspect(path4.directory.length(), content="0")
  match path4.file {
    Some(file) => {
      inspect(file.base.0, content="README")
      inspect(file.extension, content="md")
    }
    None => fail("Expected file")
  }

  // Test relative Unix path
  let path5 = UnixPath::parse("relative/path/file.txt")
  inspect(path5.directory.length(), content="2")
  inspect(path5.directory[0].0, content="relative")
  inspect(path5.directory[1].0, content="path")
  match path5.file {
    Some(file) => {
      inspect(file.base.0, content="file")
      inspect(file.extension, content="txt")
    }
    None => fail("Expected file")
  }
}