///|
pub(all) struct HostileMatrix {
  matrix : Map[Int, RouteBitSet]
  max_routes : Int
} derive(Debug)

///|
pub fn HostileMatrix::new(max_routes : Int) -> HostileMatrix {
  { matrix: Map([]), max_routes }
}

///|
pub fn HostileMatrix::set_hostile(
  self : HostileMatrix,
  r1 : @interlocking.RouteId,
  r2 : @interlocking.RouteId,
) -> Unit {
  let bs1 = match self.matrix.get(r1.id) {
    Some(bs) => bs
    None => {
      let bs = RouteBitSet::empty()
      self.matrix.set(r1.id, bs)
      bs
    }
  }
  bs1.set(r2.id)

  let bs2 = match self.matrix.get(r2.id) {
    Some(bs) => bs
    None => {
      let bs = RouteBitSet::empty()
      self.matrix.set(r2.id, bs)
      bs
    }
  }
  bs2.set(r1.id)
}

///|
pub fn HostileMatrix::are_hostile(
  self : HostileMatrix,
  r1 : @interlocking.RouteId,
  r2 : @interlocking.RouteId,
) -> Bool {
  match self.matrix.get(r1.id) {
    None => false
    Some(bs) => bs.get(r2.id)
  }
}

///|
pub fn HostileMatrix::is_conflict_with_active_mask(
  self : HostileMatrix,
  r_id : @interlocking.RouteId,
  active_mask : RouteBitSet,
) -> Bool {
  match self.matrix.get(r_id.id) {
    None => false
    Some(hostile_mask) => hostile_mask.intersects(active_mask)
  }
}

///|
pub fn HostileMatrix::build_from_interlocking_table(
  table : @interlocking.InterlockingTable,
) -> HostileMatrix {
  let hm = HostileMatrix::new(256)

  for _, rule in table.rules {
    for h_id in rule.hostile_route_ids {
      hm.set_hostile(rule.id, h_id)
    }
  }

  hm
}

///|
pub fn HostileMatrix::build_topological_conflict_table(
  table : @interlocking.InterlockingTable,
) -> HostileMatrix {
  let matrix = HostileMatrix::new(256)
  // This is intentionally built when the detector is constructed, outside the
  // 10 ms scan loop. The scan path then uses only fixed RouteBitSet masks.
  for _, rule_a in table.rules {
    for _, rule_b in table.rules {
      match detect_topological_conflicts(rule_a, rule_b) {
        Some(_) => matrix.set_hostile(rule_a.id, rule_b.id)
        None => ()
      }
    }
  }
  matrix
}