///|
pub(all) enum ParseProblem {
  BadFieldCount(Int, String)
  UnknownKind(Int, String)
} derive(Debug, Eq)

///|
pub(all) struct ParseReport {
  tokens : Array[Token]
  problems : Array[ParseProblem]
} derive(Debug, Eq)

///|
pub fn parse_tokens(input : String) -> ParseReport {
  let tokens : Array[Token] = []
  let problems : Array[ParseProblem] = []
  let lines = input.split("\n").to_array()
  for index, raw_line in lines {
    let line = raw_line.to_owned().trim().to_owned()
    if line != "" && !line.has_prefix("#") {
      let fields = [
        for field in line.split("|").to_array() => {
          field.to_owned().trim().to_owned()
        }
      ]
      if fields.length() != 4 {
        problems.push(BadFieldCount(index + 1, line))
      } else {
        match token_from_fields(fields[0], fields[1], fields[2], fields[3]) {
          Some(token) => tokens.push(token)
          None => problems.push(UnknownKind(index + 1, fields[0]))
        }
      }
    }
  }
  { tokens, problems }
}

///|
pub fn ParseProblem::message(self : ParseProblem) -> String {
  match self {
    BadFieldCount(line, text) =>
      "line \{line}: expected `kind | name | value | description`, got `\{text}`"
    UnknownKind(line, kind) => "line \{line}: unknown token kind `\{kind}`"
  }
}

///|
fn token_from_fields(
  kind : String,
  name : String,
  value : String,
  description : String,
) -> Token? {
  match kind {
    "color" => Some(Token::color(name, value, description~))
    "font-size" | "font" => Some(Token::font_size(name, value, description~))
    "spacing" | "space" => Some(Token::spacing(name, value, description~))
    "radius" => Some(Token::radius(name, value, description~))
    "shadow" => Some(Token::shadow(name, value, description~))
    _ => None
  }
}