use comfy_table::{Attribute, Cell, CellAlignment, ContentArrangement};
use crossterm::style::Stylize;
use num_format::{Locale, ToFormattedString};
use solp::ast::Solution;
use solp::{msbuild, Consume};
use std::cell::RefCell;
use std::collections::{BTreeMap, BTreeSet};
use std::fmt;
use std::fmt::Display;
use crate::error::Collector;
use crate::{calculate_percent, ux};
pub struct Info {
total_projects: BTreeMap<String, i32>,
projects_in_solutions: BTreeMap<String, i32>,
solutions: i32,
errors: RefCell<Collector>,
}
impl Info {
#[must_use]
pub fn new() -> Self {
Self {
total_projects: BTreeMap::new(),
projects_in_solutions: BTreeMap::new(),
solutions: 0,
errors: RefCell::new(Collector::new()),
}
}
}
impl Default for Info {
fn default() -> Self {
Self::new()
}
}
impl Consume for Info {
fn ok(&mut self, path: &str, solution: &Solution) {
self.solutions += 1;
let mut projects_by_type: BTreeMap<&str, i32> = BTreeMap::new();
for prj in &solution.projects {
if msbuild::is_solution_folder(prj.type_id) {
continue;
}
*projects_by_type.entry(prj.type_descr).or_insert(0) += 1;
}
let mut solution_table = ux::create_solution_table(path);
solution_table.set_content_arrangement(ContentArrangement::Disabled);
let mut table = ux::new_table();
table.add_row(vec![
Cell::new("Format"),
Cell::new(solution.format).add_attribute(Attribute::Bold),
]);
if !solution.product.is_empty() {
table.add_row(vec![
Cell::new("Product"),
Cell::new(solution.product).add_attribute(Attribute::Bold),
]);
}
for version in &solution.versions {
table.add_row(vec![
Cell::new(version.name),
Cell::new(version.ver).add_attribute(Attribute::Bold),
]);
}
solution_table.add_row(vec![Cell::new(table)]);
let mut table = ux::new_table();
table.set_header(vec![
Cell::new("Project type").add_attribute(Attribute::Bold),
Cell::new("Count").add_attribute(Attribute::Bold),
]);
for (key, value) in &projects_by_type {
*self.total_projects.entry(String::from(*key)).or_insert(0) += *value;
*self
.projects_in_solutions
.entry(String::from(*key))
.or_insert(0) += 1;
table.add_row(vec![
Cell::new(*key),
Cell::new(*value).add_attribute(Attribute::Italic),
]);
}
solution_table.add_row(vec![Cell::new(table)]);
let configurations = solution
.solution_configs
.iter()
.map(|c| c.config)
.collect::<BTreeSet<&str>>();
let platforms = solution
.solution_configs
.iter()
.map(|c| c.platform)
.collect::<BTreeSet<&str>>();
if let Some(t) =
ux::create_one_column_table("Configuration", None, configurations.into_iter())
{
solution_table.add_row(vec![Cell::new(t)]);
}
if let Some(t) = ux::create_one_column_table("Platform", None, platforms.into_iter()) {
solution_table.add_row(vec![Cell::new(t)]);
}
println!("{solution_table}");
}
fn err(&self, path: &str) {
self.errors.borrow_mut().add_path(path);
}
}
impl Display for Info {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "{}", " Statistic:".dark_red().bold())?;
let mut table = ux::new_table();
table.set_header(vec![
Cell::new("Project type").add_attribute(Attribute::Bold),
Cell::new("Count").add_attribute(Attribute::Bold),
Cell::new("%").add_attribute(Attribute::Bold),
Cell::new("# Solutions").add_attribute(Attribute::Bold),
Cell::new("%").add_attribute(Attribute::Bold),
]);
let projects = self.total_projects.iter().fold(0, |total, p| total + *p.1);
for (key, value) in &self.total_projects {
let proj_percent = calculate_percent(*value, projects);
let in_sols = self.projects_in_solutions.get(key).unwrap();
let sol_percent = calculate_percent(*in_sols, self.solutions);
table.add_row(vec![
Cell::new(key),
Cell::new(value.to_formatted_string(&Locale::en)).add_attribute(Attribute::Italic),
Cell::new(format!("{proj_percent:.2}%")).add_attribute(Attribute::Italic),
Cell::new(in_sols.to_formatted_string(&Locale::en))
.set_alignment(CellAlignment::Right)
.add_attribute(Attribute::Italic),
Cell::new(format!("{sol_percent:.2}%")).add_attribute(Attribute::Italic),
]);
}
writeln!(f, "{table}")?;
let mut table = ux::new_table();
table.add_row(vec![
Cell::new("Total solutions"),
Cell::new(self.solutions.to_formatted_string(&Locale::en))
.add_attribute(Attribute::Italic),
]);
table.add_row(vec![
Cell::new("Total projects"),
Cell::new(projects.to_formatted_string(&Locale::en)).add_attribute(Attribute::Italic),
]);
writeln!(f, "{table}")?;
write!(f, "{}", self.errors.borrow())
}
}