use std::collections::{BTreeSet, HashMap, VecDeque};
use std::sync::Arc;
use crate::card::SavedCard;
use crate::common::{get_last_modified, system_time_as_unix_time};
use crate::Id;
#[derive(Debug, Default)]
pub struct CardCache(HashMap<Id, Arc<SavedCard>>);
impl CardCache {
fn maybe_update(&mut self, id: Id) {
let card_needs_update = match self.0.get(&id) {
Some(cached_card) => {
let path = cached_card.as_path();
if path.exists() {
let metadata = std::fs::metadata(path.as_path()).unwrap();
let last_modified_time = system_time_as_unix_time(metadata.modified().unwrap());
Some(last_modified_time > cached_card.last_modified())
} else {
None
}
}
None => None, };
match card_needs_update {
Some(true) => {
let path = self.0.get(&id).unwrap().as_path();
let updated_card = SavedCard::from_path(path.as_path());
self.0.insert(id, updated_card.into());
}
Some(false) => {}
None => {
if let Some(card) = SavedCard::from_id(&id) {
self.0.insert(id, card.into());
};
}
};
}
pub fn ids_as_vec(&self) -> Vec<Id> {
self.0.keys().copied().collect()
}
pub fn all_ids(&self) -> Vec<Id> {
let mut pairs: Vec<_> = self.0.iter().collect();
pairs.sort_by_key(|&(_, v)| {
if v.is_outdated() {
get_last_modified(v.as_path())
} else {
v.last_modified().to_owned()
}
});
pairs.reverse();
pairs.into_iter().map(|(k, _)| k.to_owned()).collect()
}
pub fn exists(&self, id: &Id) -> bool {
self.0.get(id).is_some()
}
pub fn insert(&mut self, card: SavedCard) {
let id = card.id();
self.0.insert(id, card.into());
}
pub fn remove(&mut self, id: Id) {
self.0.remove(&id);
}
pub fn dependencies(&mut self, id: Id) -> BTreeSet<Id> {
let Some(card) = self.try_get_ref(id) else {
return Default::default();
};
card.dependency_ids()
.iter()
.map(ToOwned::to_owned)
.collect()
}
pub fn dependents(&mut self, id: Id) -> BTreeSet<Id> {
let Some(card) = self.try_get_ref(id) else {
return Default::default();
};
card.dependent_ids().iter().map(ToOwned::to_owned).collect()
}
pub fn recursive_dependencies(&mut self, id: Id) -> BTreeSet<Id> {
let mut dependencies = BTreeSet::new();
let mut stack = VecDeque::new();
stack.push_back(id);
while let Some(card) = stack.pop_back() {
if !dependencies.contains(&card) {
dependencies.insert(card);
let card_dependencies = self.dependencies(card);
for dependency in card_dependencies {
stack.push_back(dependency);
}
}
}
dependencies.remove(&id);
dependencies
}
pub fn recursive_dependents(&mut self, id: Id) -> BTreeSet<Id> {
let mut dependencies = BTreeSet::new();
let mut stack = VecDeque::new();
stack.push_back(id);
while let Some(card) = stack.pop_back() {
if !dependencies.contains(&card) {
dependencies.insert(card);
let card_dependencies = self.dependents(card);
for dependency in card_dependencies {
stack.push_back(dependency);
}
}
}
dependencies.remove(&id);
dependencies
}
pub fn try_get_ref(&mut self, id: Id) -> Option<Arc<SavedCard>> {
self.maybe_update(id);
self.0.get(&id).cloned()
}
pub fn get_owned(&mut self, id: Id) -> SavedCard {
(*self.get_ref(id)).clone()
}
pub fn get_ref(&mut self, id: Id) -> Arc<SavedCard> {
self.try_get_ref(id).unwrap()
}
pub fn new() -> Self {
let mut cache = Self::default();
cache.cache_all();
cache
}
pub fn refresh(&mut self) {
*self = Self::new();
}
fn cache_all(&mut self) {
let all_cards = SavedCard::load_all_cards();
for card in all_cards {
self.cache_one(card);
}
}
pub fn cache_one(&mut self, card: SavedCard) {
self.0.insert(card.id(), card.into());
}
pub fn new_empty() -> Self {
CardCache(HashMap::new())
}
}