///|
pub enum RuleKind {
  RequiredUnits
  UniqueInputNames
  UniqueResultNames
  FormulaVariables
  SourceCitations
} derive(Debug, Eq)

///|
pub fn rule_kinds() -> Array[RuleKind] {
  [
    RequiredUnits,
    UniqueInputNames,
    UniqueResultNames,
    FormulaVariables,
    SourceCitations,
  ]
}

///|
pub struct RuleIssue {
  rule : RuleKind
  location : String
  message : String
} derive(Debug, Eq)

///|
fn rule_issue(
  rule : RuleKind,
  location : String,
  message : String,
) -> RuleIssue {
  { rule, location, message }
}

///|
fn repeated(values : Array[String]) -> Array[String] {
  let duplicates : Array[String] = []
  for index, value in values {
    for previous in values[:index] {
      if previous == value && !duplicates.contains(value) {
        duplicates.push(value)
      }
    }
  }
  duplicates
}

///|
pub fn ChemReport::check_rules(
  self : ChemReport,
  rules : Array[RuleKind],
) -> Array[RuleIssue] {
  let issues : Array[RuleIssue] = []
  for rule in rules {
    match rule {
      RequiredUnits => {
        for item in self.inputs {
          if item.value.unit.trim() == "" {
            issues.push(rule_issue(rule, item.name, "input unit is empty"))
          }
        }
        for item in self.results {
          if item.value.unit.trim() == "" {
            issues.push(rule_issue(rule, item.name, "result unit is empty"))
          }
        }
      }
      UniqueInputNames => {
        let names = [ for item in self.inputs => item.name ]
        for name in repeated(names) {
          issues.push(rule_issue(rule, name, "input name is repeated"))
        }
      }
      UniqueResultNames => {
        let names = [ for item in self.results => item.name ]
        for name in repeated(names) {
          issues.push(rule_issue(rule, name, "result name is repeated"))
        }
      }
      FormulaVariables => {
        let known : Array[String] = []
        for item in self.inputs {
          known.push(item.name)
        }
        for item in self.results {
          known.push(item.name)
        }
        for item in self.formulas {
          for variable in item.variables {
            if !known.contains(variable) {
              issues.push(
                rule_issue(rule, item.name, "formula variable is not recorded"),
              )
            }
          }
        }
      }
      SourceCitations =>
        for item in self.sources {
          if item.citation.trim() == "" {
            issues.push(
              rule_issue(rule, item.label, "source citation is empty"),
            )
          }
        }
    }
  }
  issues
}