use liwe::graph::basic_iter::GraphNodePointer;
use rayon::prelude::*;
use serde::Serialize;
use liwe::model::node::Node;
use liwe::graph::{Graph, GraphContext};
use liwe::model::node::{NodeIter, NodePointer};
#[derive(Debug, Clone, Serialize, Default)]
pub struct KeyStatistics {
pub key: String,
pub title: String,
pub sections: usize,
pub paragraphs: usize,
pub lines: usize,
pub words: usize,
pub incoming_block_refs: usize,
pub incoming_inline_refs: usize,
pub total_incoming_refs: usize,
pub outgoing_block_refs: usize,
pub outgoing_inline_refs: usize,
pub total_connections: usize,
pub bullet_lists: usize,
pub ordered_lists: usize,
pub code_blocks: usize,
pub tables: usize,
pub quotes: usize,
}
impl KeyStatistics {
pub fn new(key: String, title: String) -> Self {
Self {
key,
title,
..Default::default()
}
}
pub fn count_node(&mut self, node: &liwe::model::node::Node) {
match node {
Node::Section(_) => self.sections += 1,
Node::Leaf(_) => self.paragraphs += 1,
Node::BulletList() => self.bullet_lists += 1,
Node::OrderedList() => self.ordered_lists += 1,
Node::Raw(_, _) => self.code_blocks += 1,
Node::Table(_) => self.tables += 1,
Node::Quote() => self.quotes += 1,
_ => {}
}
}
pub fn merge(mut self, other: Self) -> Self {
self.sections += other.sections;
self.paragraphs += other.paragraphs;
self.lines += other.lines;
self.words += other.words;
self.incoming_block_refs += other.incoming_block_refs;
self.incoming_inline_refs += other.incoming_inline_refs;
self.total_incoming_refs += other.total_incoming_refs;
self.outgoing_block_refs += other.outgoing_block_refs;
self.outgoing_inline_refs += other.outgoing_inline_refs;
self.total_connections += other.total_connections;
self.bullet_lists += other.bullet_lists;
self.ordered_lists += other.ordered_lists;
self.code_blocks += other.code_blocks;
self.tables += other.tables;
self.quotes += other.quotes;
self
}
fn count_nodes_recursive<'a, T: NodeIter<'a> + NodePointer<'a>>(
iter: &T,
stats: &mut KeyStatistics,
graph: &'a Graph,
) {
if let Some(node) = iter.node() {
stats.count_node(&node);
if let Some(id) = iter.id() {
if let Some(line_id) = graph.graph_node(id).line_id() {
stats.outgoing_inline_refs += graph.get_line(line_id).ref_keys().len();
}
}
}
if let Some(child) = iter.child() {
Self::count_nodes_recursive(&child, stats, graph);
let mut current = child;
while let Some(next) = current.next() {
Self::count_nodes_recursive(&next, stats, graph);
current = next;
}
}
}
pub fn from_graph(graph: &Graph) -> Vec<KeyStatistics> {
let mut key_stats: Vec<KeyStatistics> = graph
.keys()
.par_iter()
.map(|key| {
let key_str = key.to_string();
let title = graph.get_ref_text(key).unwrap_or_else(|| key.to_string());
let mut stats = KeyStatistics {
key: key_str,
title,
..Default::default()
};
if let Some(node_id) = graph.get_node_id(key) {
let root = GraphNodePointer::new(graph, node_id);
Self::count_nodes_recursive(&root, &mut stats, graph);
}
if let Some(content) = graph.get_document(key) {
stats.lines = content.lines().count();
stats.words = content.split_whitespace().count();
}
stats.incoming_block_refs = graph.get_block_references_to(key).len();
stats.incoming_inline_refs = graph.get_inline_references_to(key).len();
stats.total_incoming_refs = stats.incoming_block_refs + stats.incoming_inline_refs;
stats.outgoing_block_refs = graph.get_block_references_in(key).len();
stats.total_connections = stats.incoming_block_refs
+ stats.incoming_inline_refs
+ stats.outgoing_block_refs
+ stats.outgoing_inline_refs;
stats
})
.collect();
key_stats.par_sort_by(|a, b| a.key.cmp(&b.key));
key_stats
}
}