///|
/// Counts derived from one immutable conversion result.
pub struct ConversionStats {
  source_scalar_value : Int
  output_token_value : Int
  pinyin_token_value : Int
  literal_token_value : Int
  phrase_decision_value : Int
  unicode_decision_value : Int
  preserved_unknown_value : Int
  diagnostic_value : Int
  ambiguous_diagnostic_value : Int
} derive(Eq, Debug)

///|
/// Summarizes token decisions without rerunning conversion.
pub fn analyze_conversion(result : ConversionResult) -> ConversionStats {
  let mut pinyin_tokens = 0
  let mut literal_tokens = 0
  let mut phrase_decisions = 0
  let mut unicode_decisions = 0
  let mut preserved_unknown = 0
  let mut ambiguous_diagnostics = 0
  let tokens = result.tokens()
  let diagnostics = result.diagnostics()
  for token in tokens {
    match token.kind() {
      PinyinToken => pinyin_tokens = pinyin_tokens + 1
      LiteralToken => literal_tokens = literal_tokens + 1
    }
    match token.decision_source() {
      PhraseLexicon => phrase_decisions = phrase_decisions + 1
      UnicodeReading => unicode_decisions = unicode_decisions + 1
      UnknownPreserved => preserved_unknown = preserved_unknown + 1
    }
  }
  for item in diagnostics {
    if item.code() == "ambiguous" {
      ambiguous_diagnostics = ambiguous_diagnostics + 1
    }
  }
  {
    source_scalar_value: text_code_points(result.source()).length(),
    output_token_value: tokens.length(),
    pinyin_token_value: pinyin_tokens,
    literal_token_value: literal_tokens,
    phrase_decision_value: phrase_decisions,
    unicode_decision_value: unicode_decisions,
    preserved_unknown_value: preserved_unknown,
    diagnostic_value: diagnostics.length(),
    ambiguous_diagnostic_value: ambiguous_diagnostics,
  }
}

///|
pub fn ConversionStats::source_scalars(self : ConversionStats) -> Int {
  self.source_scalar_value
}

///|
pub fn ConversionStats::output_tokens(self : ConversionStats) -> Int {
  self.output_token_value
}

///|
pub fn ConversionStats::pinyin_tokens(self : ConversionStats) -> Int {
  self.pinyin_token_value
}

///|
pub fn ConversionStats::literal_tokens(self : ConversionStats) -> Int {
  self.literal_token_value
}

///|
pub fn ConversionStats::phrase_decisions(self : ConversionStats) -> Int {
  self.phrase_decision_value
}

///|
pub fn ConversionStats::unicode_decisions(self : ConversionStats) -> Int {
  self.unicode_decision_value
}

///|
pub fn ConversionStats::preserved_unknown(self : ConversionStats) -> Int {
  self.preserved_unknown_value
}

///|
pub fn ConversionStats::diagnostics(self : ConversionStats) -> Int {
  self.diagnostic_value
}

///|
pub fn ConversionStats::ambiguous_diagnostics(self : ConversionStats) -> Int {
  self.ambiguous_diagnostic_value
}