use crate::dictionary::app_data_dir; use crate::lang::WordOpenMode; use chrono::{DateTime, Utc}; use std::fs::{File, OpenOptions}; use std::io::Write; use std::io::{BufRead, BufReader}; use std::path::PathBuf; const MAX_HISTORY_LENGTH: usize = 1000; pub fn get_history_of_set(id: u32) -> Vec { let app_dir = app_data_dir(); let head = app_dir.clone().join(format!("set_{}_history.csv", id)); let tail = app_dir.clone().join(format!("set_{}_history_tail.csv", id)); let mut lines = Vec::new(); append_lines_if_exists(tail, &mut lines); append_lines_if_exists(head, &mut lines); parse_history_items(lines) } fn append_lines_if_exists(path: PathBuf, lines: &mut Vec) { if path.exists() { let reader = BufReader::new(File::open(path).unwrap()); for line in reader.lines() { lines.push(line.unwrap()); } } } fn parse_history_items(strings: Vec) -> Vec { let mut items = Vec::with_capacity(strings.len()); for string in strings { if let [time, word, mode, before, after] = string.split(';').collect::>()[..] { items.push(HistoryItem { timestamp: DateTime::from_timestamp(time.parse().unwrap(), 0).unwrap(), word_id: word.parse::().unwrap(), mode: match mode.parse::().unwrap() { 2 => WordOpenMode::Hard, 3 => WordOpenMode::Ok, 4 => WordOpenMode::Easy, _ => WordOpenMode::None, }, before: before.parse().unwrap(), after: after.parse().unwrap(), }); } } items } pub fn push_note(set_id: u32, item: HistoryItem) { let app_dir = app_data_dir(); let path = app_dir.clone().join(format!("set_{}_history.csv", set_id)); let mut file = OpenOptions::new().create(true).append(true).open(path).unwrap(); let line_str = format!("{};{};{};{};{}", item.timestamp.timestamp(), item.word_id, match item.mode { WordOpenMode::Easy => 4, WordOpenMode::Ok => 3, WordOpenMode::Hard => 2, WordOpenMode::None => 1 }, item.before, item.after); writeln!(&mut file, "{}", line_str.to_string()).unwrap(); } #[derive(Clone)] pub struct HistoryItem { pub timestamp: DateTime, pub word_id: u32, pub mode: WordOpenMode, pub before: u8, pub after: u8, }