///|
/// Reading evidence for one Unicode scalar from the source text.
pub struct ScalarReadingEvidence {
  code_value : Int
  original_value : String
  source_span : SourceSpan
  candidate_values : Array[String]
} derive(Eq, Debug)

///|
/// Ordered scalar evidence and aggregate lookup counts.
pub struct ReadingInspection {
  entry_values : Array[ScalarReadingEvidence]
  known_value : Int
  unknown_value : Int
  ambiguous_value : Int
} derive(Eq, Debug)

///|
fn copy_scalar_evidence(
  values : Array[ScalarReadingEvidence],
) -> Array[ScalarReadingEvidence] {
  let output : Array[ScalarReadingEvidence] = []
  for value in values {
    output.push(value)
  }
  output
}

///|
/// Inspects Unicode readings without applying phrase or ambiguity policies.
pub fn inspect_text_readings(source : String) -> ReadingInspection {
  let entries : Array[ScalarReadingEvidence] = []
  let codes = text_code_points(source)
  let mut known = 0
  let mut unknown = 0
  let mut ambiguous = 0
  for index = 0; index < codes.length(); index = index + 1 {
    let code = codes[index]
    let candidates = match lookup_readings(code) {
      None => {
        unknown = unknown + 1
        []
      }
      Some(reading_set) => {
        known = known + 1
        let values = reading_set.readings()
        if values.length() > 1 {
          ambiguous = ambiguous + 1
        }
        values
      }
    }
    entries.push({
      code_value: code,
      original_value: code_points_text([code]),
      source_span: source_span(index, index + 1).unwrap(),
      candidate_values: candidates,
    })
  }
  {
    entry_values: entries,
    known_value: known,
    unknown_value: unknown,
    ambiguous_value: ambiguous,
  }
}

///|
pub fn ScalarReadingEvidence::code_point(self : ScalarReadingEvidence) -> Int {
  self.code_value
}

///|
pub fn ScalarReadingEvidence::original(self : ScalarReadingEvidence) -> String {
  self.original_value
}

///|
pub fn ScalarReadingEvidence::span(self : ScalarReadingEvidence) -> SourceSpan {
  self.source_span
}

///|
pub fn ScalarReadingEvidence::candidates(
  self : ScalarReadingEvidence,
) -> Array[String] {
  self.candidate_values.copy()
}

///|
pub fn ScalarReadingEvidence::is_known(self : ScalarReadingEvidence) -> Bool {
  self.candidate_values.length() > 0
}

///|
pub fn ScalarReadingEvidence::is_ambiguous(
  self : ScalarReadingEvidence,
) -> Bool {
  self.candidate_values.length() > 1
}

///|
pub fn ReadingInspection::entries(
  self : ReadingInspection,
) -> Array[ScalarReadingEvidence] {
  copy_scalar_evidence(self.entry_values)
}

///|
pub fn ReadingInspection::total_scalars(self : ReadingInspection) -> Int {
  self.entry_values.length()
}

///|
pub fn ReadingInspection::known_scalars(self : ReadingInspection) -> Int {
  self.known_value
}

///|
pub fn ReadingInspection::unknown_scalars(self : ReadingInspection) -> Int {
  self.unknown_value
}

///|
pub fn ReadingInspection::ambiguous_scalars(self : ReadingInspection) -> Int {
  self.ambiguous_value
}