///|
pub fn url_path(url_or_path : String) -> String {
  let text = trim_ascii(url_or_path)
  if text == "" {
    return "/"
  }
  normalize_path(strip_fragment(strip_scheme_and_authority(text)))
}

///|
pub fn url_path_without_query(url_or_path : String) -> String {
  let path = url_path(url_or_path)
  match path.find("?") {
    Some(index) => path.unsafe_substring(start=0, end=index)
    None => path
  }
}

///|
pub fn url_query(url_or_path : String) -> String? {
  let path = url_path(url_or_path)
  match path.find("?") {
    Some(index) if index + 1 < path.length() =>
      Some(path.unsafe_substring(start=index + 1, end=path.length()))
    Some(_) => Some("")
    None => None
  }
}

///|
pub fn strip_fragment(text : String) -> String {
  match text.find("#") {
    Some(index) => text.unsafe_substring(start=0, end=index)
    None => text
  }
}

///|
pub fn strip_scheme_and_authority(text : String) -> String {
  match text.find("://") {
    Some(index) => {
      let rest = text.unsafe_substring(start=index + 3, end=text.length())
      match rest.find("/") {
        Some(path_start) =>
          rest.unsafe_substring(start=path_start, end=rest.length())
        None => "/"
      }
    }
    None => text
  }
}

///|
pub fn can_fetch_url(text : String, agent : String, url : String) -> Bool {
  allowed(text, agent, url_path(url))
}

///|
pub fn decide_url(robots : Robots, agent : String, url : String) -> Decision {
  decide(robots, agent, url_path(url))
}

///|
pub fn explain_urls(
  text : String,
  agent : String,
  urls : Array[String],
) -> String {
  let paths : Array[String] = []
  for url in urls {
    paths.push(url_path(url))
  }
  explain(text, agent, paths)
}

///|
pub fn url_host(url : String) -> String? {
  match url.find("://") {
    Some(index) => {
      let rest = url.unsafe_substring(start=index + 3, end=url.length())
      let host_port = match rest.find("/") {
        Some(path_start) => rest.unsafe_substring(start=0, end=path_start)
        None => rest
      }
      let host = match host_port.find(":") {
        Some(colon) => host_port.unsafe_substring(start=0, end=colon)
        None => host_port
      }
      if host == "" {
        None
      } else {
        Some(host)
      }
    }
    None => None
  }
}

///|
pub fn host_matches_robots(robots : Robots, url : String) -> Bool {
  if robots.hosts.is_empty() {
    return true
  }
  match url_host(url) {
    Some(host) => contains_string_case_insensitive(robots.hosts, host)
    None => false
  }
}

///|
pub fn contains_string_case_insensitive(
  values : Array[String],
  value : String,
) -> Bool {
  let needle = lower_ascii(value)
  for item in values {
    if lower_ascii(item) == needle {
      return true
    }
  }
  false
}