///|
pub(all) enum RuleCategory {
  Structure
  Connectivity
  Width
  Driving
  ControlFlow
} derive(Eq, Debug)

///|
pub fn rule_category(code : String) -> RuleCategory {
  match code {
    "RTL101" | "RTL102" => Structure
    "RTL205" | "RTL206" => Connectivity
    "RTL204" => Width
    "RTL201" | "RTL202" | "RTL203" => Driving
    "RTL207" => ControlFlow
    _ => Structure
  }
}

///|
pub fn Rule::category(self : Rule) -> RuleCategory {
  rule_category(self.code())
}

///|
pub fn rules_in_category(category : RuleCategory) -> Array[Rule] {
  let result : Array[Rule] = []
  for rule in default_rules() {
    if rule.category() == category {
      result.push(rule)
    }
  }
  result
}

///|
pub fn category_codes(category : RuleCategory) -> Array[String] {
  rules_in_category(category).map(fn(rule) { rule.code() })
}

///|
pub fn config_for_category(
  config : LintConfig,
  category : RuleCategory,
) -> LintConfig {
  let mut result = config
  for rule in rules_in_category(category) {
    if !config.is_enabled(rule.code()) {
      result = result.disable(rule.code())
    }
  }
  result
}

///|
pub fn LintConfig::disable_category(
  self : LintConfig,
  category : RuleCategory,
) -> LintConfig {
  config_for_category(self, category)
}

///|
pub fn LintConfig::enable_category(
  self : LintConfig,
  category : RuleCategory,
) -> LintConfig {
  let mut result = self
  for rule in rules_in_category(category) {
    result = result.enable(rule.code())
  }
  result
}

///|
pub fn LintConfig::disabled_codes(self : LintConfig) -> Array[String] {
  let result : Array[String] = []
  for code in self.disabled {
    result.push(code)
  }
  result
}

///|
pub fn LintConfig::enabled_code_count(self : LintConfig) -> Int {
  self.active_rules().length()
}

///|
pub fn LintConfig::has_unknown_rules(self : LintConfig) -> Bool {
  self.unknown_disabled_rules().length() > 0
}

///|
pub fn lint_category_summary(config : LintConfig) -> String {
  let names : Array[String] = []
  for category in [Structure, Connectivity, Width, Driving, ControlFlow] {
    let label = match category {
      Structure => "structure"
      Connectivity => "connectivity"
      Width => "width"
      Driving => "driving"
      ControlFlow => "control-flow"
    }
    let count = config_for_category(config, category).enabled_code_count()
    names.push(label + "=" + count.to_string())
  }
  names.join(", ")
}

///|
pub fn annotate_lint_diagnostics(
  diagnostics : Array[@diagnostic.Diagnostic],
) -> Array[@diagnostic.Diagnostic] {
  diagnostics.map(fn(diagnostic) {
    diagnostic
    .with_rule(diagnostic.code)
    .with_note(
      match rule_category(diagnostic.code) {
        Structure => "structure rule"
        Connectivity => "connectivity rule"
        Width => "width rule"
        Driving => "driving rule"
        ControlFlow => "control-flow rule"
      },
    )
  })
}