use super::{
NNS_TOPOLOGY_REGIONS_REPORT_SCHEMA_VERSION, NnsTopologyRegionRow, NnsTopologyRegionsReport,
};
use crate::nns::data_center::NnsDataCenterRow;
use std::collections::BTreeMap;
pub(super) fn topology_regions_report_from_rows(
network: String,
source_endpoint: String,
data_centers: &[NnsDataCenterRow],
) -> NnsTopologyRegionsReport {
let mut region_map = BTreeMap::<String, NnsTopologyRegionRow>::new();
for data_center in data_centers {
let row = region_map
.entry(data_center.region.clone())
.or_insert_with(|| NnsTopologyRegionRow {
region: data_center.region.clone(),
data_center_count: 0,
node_operator_count: 0,
node_provider_count: 0,
node_count: 0,
});
row.data_center_count = row.data_center_count.saturating_add(1);
row.node_operator_count = row
.node_operator_count
.saturating_add(u64::from(data_center.node_operator_count));
row.node_provider_count = row
.node_provider_count
.saturating_add(u64::from(data_center.node_provider_count));
row.node_count = row
.node_count
.saturating_add(u64::from(data_center.node_count));
}
let mut regions = region_map.into_values().collect::<Vec<_>>();
regions.sort_by(|left, right| {
(
std::cmp::Reverse(left.node_count),
std::cmp::Reverse(left.data_center_count),
left.region.as_str(),
)
.cmp(&(
std::cmp::Reverse(right.node_count),
std::cmp::Reverse(right.data_center_count),
right.region.as_str(),
))
});
let (node_operator_count, node_provider_count, node_count) =
regions
.iter()
.fold((0, 0, 0), |(operators, providers, nodes), row| {
(
operators + row.node_operator_count,
providers + row.node_provider_count,
nodes + row.node_count,
)
});
NnsTopologyRegionsReport {
schema_version: NNS_TOPOLOGY_REGIONS_REPORT_SCHEMA_VERSION,
network,
source_endpoint,
data_center_count: data_centers.len(),
node_operator_count,
node_provider_count,
node_count,
regions,
}
}