1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use crate::level::TaskLevel;
use serde::{Deserialize, Serialize};
use std::{
    collections::BTreeSet,
    time::{Duration, SystemTime},
};

pub mod task_facade;

#[derive(Debug, Clone)]
pub enum Feedback<'a, I: Iterator<Item = &'a String>> {
    CorrectAnswer,
    WrongAnswer {
        correct_answers: I,
        explanation: &'a Option<String>,
    },
}

#[derive(Serialize, Deserialize)]
#[serde(bound(deserialize = "Level: TaskLevel"))]
pub struct Task<Level>
where
    Level: TaskLevel,
{
    level: Level,
    last_repetition_time: SystemTime,
    description: String,
    correct_answers: BTreeSet<String>,
    explanation: Option<String>,
}

impl<Level> Task<Level>
where
    Level: TaskLevel,
{
    /// O(1)
    pub fn new(
        description: String,
        correct_answers: BTreeSet<String>,
        explanation: Option<String>,
    ) -> Self {
        Self {
            level: Level::default(),
            last_repetition_time: SystemTime::now(),
            description,
            correct_answers,
            explanation,
        }
    }

    /// O(1)
    pub fn get_desctiption(&self) -> &str {
        &self.description
    }

    /// O(1)
    pub fn until_next_repetition(&self) -> Duration {
        (self.last_repetition_time + self.level.duration())
            .duration_since(SystemTime::now())
            .unwrap_or_default()
    }

    /// O(log(correct_answers))
    pub fn complete(
        &mut self,
        respondent: impl FnOnce(&String) -> String,
    ) -> Feedback<impl Iterator<Item = &String>> {
        self.last_repetition_time = SystemTime::now();
        match self
            .correct_answers
            .contains(&respondent(&self.description))
        {
            true => {
                self.level.success();
                Feedback::CorrectAnswer
            }
            false => {
                self.level.failure();
                Feedback::WrongAnswer {
                    correct_answers: self.correct_answers.iter(),
                    explanation: &self.explanation,
                }
            }
        }
    }
}