use crate::{game::AnkiDB, storage::Storage};
use serde::{Deserialize, Serialize};
use std::{
ops::Deref,
time::{Duration, SystemTime},
};
#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Fact {
pub term: String,
pub definition: String,
}
impl Fact {
pub fn new(term: impl Into<String>, definition: impl Into<String>) -> Self {
Self {
term: term.into(),
definition: definition.into(),
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Item {
pub fact: Fact,
pub(crate) last_tested: Option<SystemTime>,
pub(crate) history: Vec<bool>,
}
impl From<Fact> for Item {
fn from(f: Fact) -> Self {
Self::new(f)
}
}
impl Item {
#[must_use]
pub(crate) const fn new(fact: Fact) -> Self {
Self {
fact,
last_tested: None,
history: vec![],
}
}
#[must_use]
#[allow(dead_code)]
pub(crate) const fn all_parts(fact: Fact, last_tested: SystemTime, history: Vec<bool>) -> Self {
Self {
fact,
last_tested: Some(last_tested),
history,
}
}
#[must_use]
pub fn get_streak(&self) -> u32 {
let min = if self.history.contains(&true) && self.true_streak() > 0 {
1
} else {
0
};
let mut count = 0;
for b in &self.history {
if *b {
count += 1;
} else {
count /= 2;
}
}
count.min(min)
}
pub(crate) fn true_streak(&self) -> u32 {
let mut count = 0;
for b in &self.history {
if *b {
count += 1;
} else {
count = 0;
}
}
count
}
#[must_use]
pub fn time_since_last_test(&self) -> Option<Duration> {
if let Some(st) = self.last_tested {
if let Ok(d) = st.elapsed() {
return Some(d);
}
}
None
}
}
#[derive(Debug)] pub struct ItemGuard<'a, S: Storage> {
v: &'a mut AnkiDB,
index: usize,
s: &'a mut S,
pub was_succesful: Option<bool>,
}
impl<'a, S: Storage> Drop for ItemGuard<'a, S> {
fn drop(&mut self) {
if let Some(ws) = self.was_succesful {
self.v[self.index].history.push(ws);
self.v[self.index].last_tested = Some(SystemTime::now());
self.s.write_db(self.v).unwrap();
}
}
}
impl<'a, S: Storage> Deref for ItemGuard<'a, S> {
type Target = Fact;
fn deref(&self) -> &Self::Target {
&self.v[self.index].fact
}
}
impl<'a, S: Storage> ItemGuard<'a, S> {
pub(crate) fn new(v: &'a mut AnkiDB, index: usize, s: &'a mut S) -> Self {
Self {
v,
index,
was_succesful: None,
s,
}
}
}