///|
fn trim_trailing_slashes(path : String) -> String {
  if path == "/" {
    "/"
  } else {
    path.trim_end(chars="/").to_owned()
  }
}

///|
fn trim_leading_slashes(path : String) -> String {
  path.trim_start(chars="/").to_owned()
}

///|
fn collapse_slashes(path : String) -> String {
  let parts = path.split("/")
  let kept = parts.filter(part => part != "").map(part => part.to_owned())
  if path.has_prefix("/") {
    "/" + kept.join("/")
  } else {
    kept.join("/")
  }
}

///|
fn normalize_path(path : String) -> String {
  let unix = path.replace_all(old="\\", new="/")
  let collapsed = collapse_slashes(unix)
  let trimmed = trim_trailing_slashes(collapsed)
  if trimmed == "" {
    "."
  } else {
    trimmed
  }
}

///|
fn join_path(parent : String, child : String) -> String {
  let parent = trim_trailing_slashes(normalize_path(parent))
  let child = trim_leading_slashes(normalize_path(child))
  if parent == "" || parent == "." {
    if child == "" || child == "." {
      "."
    } else {
      child
    }
  } else if child == "" || child == "." {
    parent
  } else if parent == "/" {
    "/" + child
  } else {
    parent + "/" + child
  }
}

///|
fn path_basename(path : String) -> String {
  let path = normalize_path(path)
  if path == "" {
    "."
  } else if path == "/" {
    "/"
  } else {
    match path.rev_split_once("/") {
      Some((_, base)) => base.to_owned()
      None => path
    }
  }
}

///|
fn path_dirname(path : String) -> String {
  let path = normalize_path(path)
  if path == "/" {
    "/"
  } else {
    match path.rev_split_once("/") {
      Some((dir, _)) => if dir == "" { "/" } else { dir.to_owned() }
      None => "."
    }
  }
}

///|
fn relative_path(root : String, full_path : String) -> String {
  let root = normalize_path(root)
  let full_path = normalize_path(full_path)
  match full_path.strip_prefix(root) {
    Some(path) =>
      if path == "" {
        ""
      } else if root == "/" {
        path.to_owned()
      } else if path.has_prefix("/") {
        path.trim_start(chars="/").to_owned()
      } else {
        full_path
      }
    None => full_path
  }
}

///|
fn event_path_for(path : String, options : Options) -> String {
  match options.cwd {
    Some(cwd) => relative_path(cwd, path)
    None => path
  }
}

///|
fn absolute_path_for(path : String, options : Options) -> String {
  match options.cwd {
    Some(cwd) => join_path(cwd, path)
    None => path
  }
}