///|
pub fn normalize_agent(agent : String) -> String {
  lower_ascii(trim_ascii(agent))
}

///|
pub fn agent_tokens(agent : String) -> Array[String] {
  let tokens : Array[String] = []
  let mut current = ""
  for _, ch in normalize_agent(agent) {
    if ch.is_ascii_digit() ||
      ch.is_ascii_lowercase() ||
      ch.is_ascii_uppercase() ||
      ch == '-' ||
      ch == '_' {
      current = current + [ch]
    } else if current != "" {
      tokens.push(current)
      current = ""
    }
  }
  if current != "" {
    tokens.push(current)
  }
  tokens
}

///|
pub fn agent_family(agent : String) -> String {
  let tokens = agent_tokens(agent)
  if tokens.is_empty() {
    ""
  } else {
    tokens[0]
  }
}

///|
pub fn agent_matches_token(agent : String, token : String) -> Bool {
  let needle = normalize_agent(token)
  if needle == "*" {
    return true
  }
  contains_string(agent_tokens(agent), needle) ||
  normalize_agent(agent).find(needle) is Some(_)
}

///|
pub fn best_agent_token(agent : String, tokens : Array[String]) -> String {
  let mut best = ""
  for token in tokens {
    if agent_matches_token(agent, token) && token.length() > best.length() {
      best = token
    }
  }
  best
}

///|
pub fn agent_score_against(agent : String, token : String) -> Int {
  if token == "*" {
    0
  } else if agent_matches_token(agent, token) {
    normalize_agent(token).length()
  } else {
    -1
  }
}

///|
pub fn rank_agents(agent : String, tokens : Array[String]) -> Array[String] {
  let result : Array[String] = []
  for token in tokens {
    result.push(token)
  }
  for i = 0; i < result.length(); i = i + 1 {
    for j = i + 1; j < result.length(); j = j + 1 {
      if agent_score_against(agent, result[j]) >
        agent_score_against(agent, result[i]) {
        let tmp = result[i]
        result[i] = result[j]
        result[j] = tmp
      }
    }
  }
  result
}

///|
pub fn agent_report(agent : String, tokens : Array[String]) -> String {
  "agent=" +
  normalize_agent(agent) +
  "\nfamily=" +
  agent_family(agent) +
  "\nbest=" +
  best_agent_token(agent, tokens)
}