use std::collections::HashSet;
use chrono::{naive, NaiveDate};
use crate::data::activity;
use crate::data::bartib_file;
use crate::data::activity::Activity;
pub struct ActivityFilter<'a> {
pub number_of_activities: Option<usize>,
pub from_date: Option<NaiveDate>,
pub to_date: Option<NaiveDate>,
pub date: Option<NaiveDate>,
pub project: Option<&'a str>
}
pub fn get_descriptions_and_projects(file_content: &[bartib_file::Line]) -> Vec<(&String, &String)> {
let mut activities : Vec<&activity::Activity> = get_activities(file_content).collect();
get_descriptions_and_projects_from_activities(&mut activities)
}
fn get_descriptions_and_projects_from_activities<'a>(activities: &mut [&'a Activity]) -> Vec<(&'a String, &'a String)> {
activities.sort_by_key(|activity| activity.start);
activities.reverse();
let mut known_descriptions_and_projects: HashSet<(&String, &String)> = HashSet::new();
let mut descriptions_and_projects: Vec<(&String, &String)> = Vec::new();
for description_and_project in activities.iter().map(|a| (&a.description, &a.project)) {
if !known_descriptions_and_projects.contains(&description_and_project) {
known_descriptions_and_projects.insert(description_and_project);
descriptions_and_projects.push(description_and_project);
}
}
descriptions_and_projects.reverse();
descriptions_and_projects
}
pub fn get_running_activities(file_content: &[bartib_file::Line]) -> Vec<&activity::Activity> {
get_activities(file_content)
.filter(|activity| !activity.is_stopped())
.collect()
}
pub fn get_activities(file_content: &[bartib_file::Line]) -> impl Iterator<Item = &activity::Activity> {
file_content
.iter()
.map(|line| line.activity.as_ref())
.filter_map(|activity_result| activity_result.ok())
}
pub fn filter_activities<'a>(
activities: impl Iterator<Item = &'a activity::Activity>,
filter: &'a ActivityFilter,
) -> impl Iterator<Item = &'a activity::Activity> {
let from_date: NaiveDate;
let to_date: NaiveDate;
if let Some(date) = filter.date {
from_date = date;
to_date = date;
} else {
from_date = filter.from_date.unwrap_or(naive::MIN_DATE);
to_date = filter.to_date.unwrap_or(naive::MAX_DATE);
}
activities
.filter(move |activity| {activity.start.date() >= from_date && activity.start.date() <= to_date})
.filter(move |activity| filter.project.map(|p| activity.project == *p).unwrap_or(true))
}
pub fn get_last_activity_by_end(file_content: &[bartib_file::Line]) -> Option<&activity::Activity> {
get_activities(file_content)
.filter(|activity| activity.is_stopped())
.max_by_key(|activity| activity.end.unwrap_or_else(||naive::MIN_DATE.and_hms(0, 0, 0)))
}
pub fn get_last_activity_by_start(file_content: &[bartib_file::Line]) -> Option<&activity::Activity> {
get_activities(file_content).max_by_key(|activity| activity.start)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get_descriptions_and_projects_test_simple() {
let a1 = activity::Activity::start("p1".to_string(), "d1".to_string(), None);
let a2 = activity::Activity::start("p1".to_string(), "d1".to_string(), None);
let a3 = activity::Activity::start("p2".to_string(), "d1".to_string(), None);
let mut activities = vec![&a1, &a2, &a3];
let descriptions_and_projects = get_descriptions_and_projects_from_activities(&mut activities);
assert_eq!(descriptions_and_projects.len(), 2);
assert_eq!(*descriptions_and_projects.get(0).unwrap(), (&"d1".to_string(), &"p1".to_string()));
assert_eq!(*descriptions_and_projects.get(1).unwrap(), (&"d1".to_string(), &"p2".to_string()));
}
#[test]
fn get_descriptions_and_projects_test_restarted_activitiy() {
let a1 = activity::Activity::start("p1".to_string(), "d1".to_string(), None);
let a2 = activity::Activity::start("p2".to_string(), "d1".to_string(), None);
let a3 = activity::Activity::start("p1".to_string(), "d1".to_string(), None);
let mut activities = vec![&a1, &a2, &a3];
let descriptions_and_projects = get_descriptions_and_projects_from_activities(&mut activities);
assert_eq!(descriptions_and_projects.len(), 2);
assert_eq!(*descriptions_and_projects.get(0).unwrap(), (&"d1".to_string(), &"p2".to_string()));
assert_eq!(*descriptions_and_projects.get(1).unwrap(), (&"d1".to_string(), &"p1".to_string()));
}
}