use calamine::Data;
use petgraph::graph::NodeIndex;
use petgraph::visit::EdgeRef;
use petgraph::{Directed, Direction, Graph};
use std::ops::{Deref, DerefMut};
use std::{
env,
fmt::{self, Formatter},
};
#[derive(Debug)]
pub struct AncestorHeader {
pub name1: String,
pub years1: String,
pub name2: String,
pub years2: String,
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct Person {
pub generation: i8,
pub name: String,
pub birthdate: String,
pub last_name: String,
pub address: String,
pub city: String,
pub landline: String,
pub mobile_number: String,
pub email: String,
}
impl Person {
pub fn new(info: Vec<String>, generation: i8) -> Result<Self, &'static str> {
let [
name,
birthdate,
last_name,
address,
city,
landline,
mobile_number,
email,
]: [String; 8] = info.try_into().map_err(|_| "Expected exactly 8 elements")?;
Ok(Person {
generation,
name,
birthdate,
last_name,
address,
city,
landline,
mobile_number,
email,
})
}
}
impl fmt::Display for Person {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.name)
}
}
#[derive(Debug, serde::Serialize)]
pub struct D3Node {
#[serde(skip_serializing_if = "Option::is_none")]
pub _children: Option<Vec<D3Node>>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub children: Vec<D3Node>,
#[serde(flatten)]
pub person: Person,
}
#[derive(Debug, PartialEq)]
pub enum Relationship {
Child,
Relative,
Married,
Divorced,
Dating,
ChildFromPartner,
}
impl fmt::Display for Relationship {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Relationship::Child => write!(f, "Child"),
Relationship::Relative => write!(f, "Relative"),
Relationship::Married => write!(f, "Married"),
Relationship::Divorced => write!(f, "Divorced"),
Relationship::Dating => write!(f, "Kærester"),
Relationship::ChildFromPartner => write!(f, "ChildFromPartner"),
}
}
}
fn relation_check(name: String) -> Relationship {
if name.contains("~") {
Relationship::Married
} else if name.contains("-/-") {
Relationship::Divorced
} else if name.contains("-") {
Relationship::Dating
} else if name.contains("- -") {
Relationship::ChildFromPartner
} else {
Relationship::Relative
}
}
pub struct FamilyGraph(pub Graph<Person, Relationship, Directed>);
impl FamilyGraph {
pub fn new() -> Self {
Self(Graph::new())
}
pub fn build_subtree(&self, node_idx: NodeIndex) -> D3Node {
let children: Vec<D3Node> = self
.edges_directed(node_idx, Direction::Outgoing)
.filter(|edge| matches!(edge.weight(), Relationship::Child))
.map(|edge| {
let child_idx = edge.target();
self.build_subtree(child_idx)
})
.collect();
D3Node {
_children: None,
children,
person: self[node_idx].clone(),
}
}
fn insert_relative(
&mut self,
crnt: &mut NodeIndex,
parent: &mut NodeIndex,
level: i8,
new_gen: i8,
person: Person,
) {
let n = level - new_gen;
let new_node = self.add_node(person);
if n == 0 || n == -1 {
if n == -1 {
*parent = *crnt;
} } else if new_gen == level {
*crnt = new_node;
return;
} else if n > 0 {
for _ in 0..n {
if let Some(grandparent) =
self.neighbors_directed(*parent, Direction::Incoming).next()
{
*parent = grandparent;
println!("Updated parent to grandparent: {:?}", grandparent);
} else {
eprintln!("No grandparent found for node {:?}", parent);
}
}
}
*crnt = new_node;
self.add_edge(*parent, *crnt, Relationship::Child);
}
fn set_common_relatives(ancestor_header: Option<AncestorHeader>) -> (Person, Person) {
let ancestors = match ancestor_header {
Some(anc) => anc,
None => {
match env::var("COMMON_ANCESTOR1") {
Ok(value) => println!("Common ancestor: {}", value),
Err(e) => {
eprintln!("Error reading COMMON_ANCESTOR1: {}", e);
eprintln!("Make sure your .env file exists and dotenv().ok() is called");
}
}
let common_ancestor1 =
env::var("COMMON_ANCESTOR1").expect("COMMON_ANCESTOR1 must be set");
let common_ancestor1_life =
env::var("COMMON_ANCESTOR1_LIFE").expect("COMMON_ANCESTOR1_LIFE must be set");
let common_ancestor1_lastname = env::var("COMMON_ANCESTOR1_LASTNAME")
.expect("COMMON_ANCESTOR1_LASTNAME must be set");
let common_ancestor2 =
env::var("COMMON_ANCESTOR2").expect("COMMON_ANCESTOR2 must be set");
let common_ancestor2_life =
env::var("COMMON_ANCESTOR2_LIFE").expect("COMMON_ANCESTOR2_LIFE must be set");
let common_ancestor2_lastname = env::var("COMMON_ANCESTOR2_LASTNAME")
.expect("COMMON_ANCESTOR2_LASTNAME must be set");
AncestorHeader {
name1: format!("{} {}", common_ancestor1, common_ancestor1_lastname),
years1: common_ancestor1_life,
name2: format!("{} {}", common_ancestor2, common_ancestor2_lastname),
years2: common_ancestor2_life,
}
}
};
(
Person {
generation: -1,
name: ancestors.name1,
birthdate: ancestors.years1,
last_name: String::new(),
address: "".to_string(),
city: "".to_string(),
landline: "".to_string(),
mobile_number: "".to_string(),
email: "".to_string(),
},
Person {
generation: -1,
name: ancestors.name2,
birthdate: ancestors.years2,
last_name: String::new(),
address: "".to_string(),
city: "".to_string(),
landline: "".to_string(),
mobile_number: "".to_string(),
email: "".to_string(),
},
)
}
fn new_with_common_relatives(ancestor_header: Option<AncestorHeader>) -> Self {
let mut family = FamilyGraph::new();
let (ancestor, wife_ancestor): (Person, Person) =
FamilyGraph::set_common_relatives(ancestor_header);
let parent = family.add_node(ancestor);
let parent_partner = family.add_node(wife_ancestor);
family.add_edge(parent, parent_partner, Relationship::Married);
family
}
pub fn create_family(
entries: Vec<Vec<&[Data]>>,
ancestor_header: Option<AncestorHeader>,
) -> Self {
let mut family = FamilyGraph::new_with_common_relatives(ancestor_header);
let mut parent = NodeIndex::new(0);
let mut crnt = parent;
let mut level: i8 = -1;
for family_group in entries {
for person in family_group {
let person_vec: Vec<String> = person.iter().map(|cell| cell.to_string()).collect();
let name = person_vec[0].clone();
if name.to_lowercase() == "navn" {
continue;
}
let new_gen = name.matches("*").count() as i8;
let relation = if new_gen == 0 {
relation_check(name)
} else {
Relationship::Relative
};
let row_info: Person =
Person::new(person_vec, new_gen).expect("Cannot create person from row");
if relation == Relationship::Relative {
family.insert_relative(&mut crnt, &mut parent, level, new_gen, row_info);
level = new_gen;
} else if relation == Relationship::ChildFromPartner {
let child = family.add_node(row_info);
family.add_edge(crnt, child, Relationship::ChildFromPartner);
} else {
let relational = family.add_node(row_info);
family.add_edge(crnt, relational, relation);
}
}
}
family
}
}
impl Default for FamilyGraph {
fn default() -> Self {
Self::new()
}
}
impl Deref for FamilyGraph {
type Target = Graph<Person, Relationship, Directed>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for FamilyGraph {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}