use std::time::Duration;
use serde::{Deserialize, Serialize};
use crate::cache::CardCache;
use crate::categories::Category;
use crate::{deserialize_duration, serialize_duration, Id};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct FilterUtil {
pub allowed_cards: Vec<Id>, pub disallowed_cards: Vec<Id>,
pub allowed_categories: Vec<Category>,
pub excluded_categories: Vec<Category>,
pub contains: Option<String>,
pub tags: Vec<String>,
pub suspended: Option<bool>,
pub resolved: Option<bool>,
pub pending: Option<bool>,
pub finished: Option<bool>,
#[serde(
serialize_with = "serialize_duration",
deserialize_with = "deserialize_duration"
)]
pub max_strength: Option<Duration>,
#[serde(
serialize_with = "serialize_duration",
deserialize_with = "deserialize_duration"
)]
pub min_strength: Option<Duration>,
#[serde(
serialize_with = "serialize_duration",
deserialize_with = "deserialize_duration"
)]
pub max_stability: Option<Duration>,
#[serde(
serialize_with = "serialize_duration",
deserialize_with = "deserialize_duration"
)]
pub min_stability: Option<Duration>,
pub max_recall_rate: Option<f32>,
pub min_recall_rate: Option<f32>,
pub max_lapses: Option<u32>,
pub all_dependencies: Option<Box<Self>>,
pub any_dependencies: Option<Box<Self>>,
pub all_dependents: Option<Box<Self>>,
pub any_dependents: Option<Box<Self>>,
}
impl FilterUtil {
pub fn new_permissive() -> Self {
Self::default()
}
pub fn new_review() -> Self {
FilterUtil {
max_recall_rate: Some(0.9),
resolved: Some(true),
suspended: Some(false),
finished: Some(true),
..Default::default()
}
}
pub fn evaluate_cards(&self, cards: Vec<Id>, cache: &mut CardCache) -> Vec<Id> {
cards
.into_iter()
.filter(|card| self.keep_card(*card, cache))
.collect()
}
pub fn keep_card(&self, card: Id, cache: &mut CardCache) -> bool {
let card = cache.get_ref(card);
if self.allowed_cards.contains(&card.id()) {
return true;
};
if self.disallowed_cards.contains(&card.id()) {
return false;
};
if !self.allowed_categories.is_empty()
&& !self
.allowed_categories
.iter()
.any(|cat| card.category() == cat)
{
return false;
}
if self
.excluded_categories
.iter()
.any(|cat| card.category() == cat)
{
return false;
}
if let Some(suspended) = self.suspended {
if card.is_suspended() != suspended {
return false;
}
}
if let Some(resolved) = self.resolved {
if card.is_resolved(cache) != resolved {
return false;
}
}
if let Some(finished) = self.finished {
if card.is_finished() != finished {
return false;
}
}
if let Some(pending) = self.pending {
if card.is_pending() != pending {
return false;
}
}
if let Some(max_strength) = self.max_strength {
if !card
.strength()
.map(|card_strength| card_strength < max_strength)
.unwrap_or(false)
{
return false;
}
}
if let Some(min_strength) = self.min_strength {
if !card
.strength()
.map(|card_strength| card_strength > min_strength)
.unwrap_or(false)
{
return false;
}
}
if let Some(max_stability) = self.max_stability {
if !card
.stability()
.map(|card_stability| card_stability < max_stability)
.unwrap_or(false)
{
return false;
}
}
if let Some(min_stability) = self.min_stability {
if !card
.stability()
.map(|card_stability| card_stability > min_stability)
.unwrap_or(false)
{
return false;
}
}
if let Some(max_recall_rate) = self.max_recall_rate {
if !card
.recall_rate()
.map(|card_recall_rate| card_recall_rate < max_recall_rate)
.unwrap_or(false)
{
return false;
}
}
if let Some(min_recall_rate) = self.min_recall_rate {
if !card
.recall_rate()
.map(|card_recall_rate| card_recall_rate > min_recall_rate)
.unwrap_or(false)
{
return false;
}
}
if let Some(search) = self.contains.as_deref() {
if !(card.front_text().contains(search) || card.back_text().contains(search)) {
return false;
}
}
if !self.tags.is_empty() && !self.tags.iter().any(|tag| card.contains_tag(tag)) {
return false;
}
if let Some(all_dependencies) = &self.all_dependencies {
let dependencies = cache.dependencies(card.id());
if !dependencies.is_empty()
&& !dependencies
.iter()
.all(|card| all_dependencies.keep_card(*card, cache))
{
return false;
}
}
if let Some(all_dependents) = &self.any_dependents {
let dependents = cache.dependents(card.id());
if !dependents.is_empty()
&& !dependents
.iter()
.all(|card| all_dependents.keep_card(*card, cache))
{
return false;
}
}
if let Some(any_dependents) = &self.any_dependents {
let dependents = cache.dependents(card.id());
if !dependents
.iter()
.any(|card| any_dependents.keep_card(*card, cache))
{
return false;
}
}
if let Some(any_depencies) = &self.any_dependencies {
let dependencies = cache.dependencies(card.id());
if dependencies
.iter()
.any(|card| any_depencies.keep_card(*card, cache))
{
return false;
}
}
true
}
}