///|
/// A prime-implicant chart. Each entry in `coverers` corresponds to the
/// minterm at the same index and contains indexes into `primes`.
pub struct CoverageChart {
  minterms : Array[Int32]
  primes : Array[Cube]
  coverers : Array[Array[Int32]]
}

///|
fn compare_cubes(left : Cube, right : Cube) -> Int32 {
  for bit in 0..> shift) & 1) == 1 {
      0
    } else if ((left.value >> shift) & 1) == 0 {
      1
    } else {
      2
    }
    let right_rank = if ((right.wildcard >> shift) & 1) == 1 {
      0
    } else if ((right.value >> shift) & 1) == 0 {
      1
    } else {
      2
    }
    if left_rank < right_rank {
      return -1
    }
    if left_rank > right_rank {
      return 1
    }
  }
  0
}

///|
/// Build a row-to-prime coverage chart from a validated table and its
/// refinement result.
pub fn make_coverage_chart(
  spec : TruthSpec,
  refinement : Refinement,
) -> CoverageChart {
  let primes = refinement.primes.copy()
  primes.sort_by(compare_cubes)
  let coverers : Array[Array[Int32]] = []
  for row in spec.on_set {
    let row_coverers : Array[Int32] = []
    for i in 0.. Array[Int32] {
  let essential : Array[Int32] = []
  for coverers in self.coverers {
    if coverers.length() == 1 {
      let index = coverers[0]
      if !essential.contains(index) {
        essential.push(index)
      }
    }
  }
  essential
}

///|
/// Return every prime implicant that uniquely covers at least one required
/// minterm, in the chart's deterministic pattern order.
pub fn CoverageChart::essential_implicants(self : CoverageChart) -> Array[Cube] {
  self.essential_indices().map(index => self.primes[index])
}

///|
test "coverage chart maps each required row to its prime implicants" {
  let spec = match TruthSpec::new(3, [7, 1, 5, 3], []) {
    Some(spec) => spec
    None => fail("valid truth table was rejected")
  }
  let chart = make_coverage_chart(spec, refine(spec))
  assert_eq(chart.minterms, [7, 1, 5, 3])
  assert_eq(chart.primes.length(), 1)
  assert_eq(chart.primes[0].pattern(), "--1")
  assert_eq(chart.coverers, [[0], [0], [0], [0]])
}

///|
test "coverage chart omits don't-care-only rows" {
  let spec = match TruthSpec::new(3, [1], [3]) {
    Some(spec) => spec
    None => fail("valid truth table was rejected")
  }
  let chart = make_coverage_chart(spec, refine(spec))
  assert_eq(chart.minterms, [1])
  assert_eq(chart.coverers, [[0]])
}

///|
test "essential implicants are the unique coverers of required rows" {
  let spec = match TruthSpec::new(3, [0, 1, 6, 7], []) {
    Some(spec) => spec
    None => fail("valid truth table was rejected")
  }
  let chart = make_coverage_chart(spec, refine(spec))
  let essential = chart.essential_implicants()
  assert_eq(essential.length(), 2)
  assert_eq(essential[0].pattern(), "00-")
  assert_eq(essential[1].pattern(), "11-")
}