use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use crate::{
project::Project,
task::{Task, TaskList},
};
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct VaultIndex {
pub next_canonical_id: u32,
pub next_canonical_project_id: u32,
pub next_friendly_id_by_project: HashMap<u32, u32>,
pub next_friendly_id_by_default: u32,
pub project_key_to_canonical_id: HashMap<String, Vec<u32>>,
pub task_friendly_id_to_canonical_id: HashMap<String, u32>,
pub task_id_to_list_name: HashMap<u32, String>,
pub task_id_to_project_id: HashMap<u32, Option<u32>>,
}
impl VaultIndex {
pub fn allocate_canonical_id(&mut self) -> u32 {
let id = self.next_canonical_id;
self.next_canonical_id += 1;
id
}
pub fn allocate_canonical_project_id(&mut self) -> u32 {
let id = self.next_canonical_project_id;
self.next_canonical_project_id += 1;
id
}
pub fn allocate_friendly_id_for_default(&mut self) -> u32 {
let id = self.next_friendly_id_by_default;
self.next_friendly_id_by_default += 1;
id
}
pub fn allocate_friendly_id_for_project(&mut self, project_id: u32) -> u32 {
let counter = self
.next_friendly_id_by_project
.entry(project_id)
.or_insert(1);
let id = *counter;
*counter += 1;
id
}
pub fn get_canonical_id_from_friendly_id(&self, friendly_id: impl Into<String>) -> Option<u32> {
self
.task_friendly_id_to_canonical_id
.get(&friendly_id.into())
.copied()
}
pub fn get_canonical_project_id_from_key(&self, project_key: impl Into<String>) -> Option<u32> {
self
.project_key_to_canonical_id
.get(&project_key.into())
.and_then(|ids| ids.last().copied())
}
pub fn get_all_canonical_project_ids_from_key(&self, project_key: impl Into<String>) -> Vec<u32> {
self
.project_key_to_canonical_id
.get(&project_key.into())
.cloned()
.unwrap_or_default()
}
pub fn get_list_name_for_task(&self, task_id: u32) -> Option<&String> {
self.task_id_to_list_name.get(&task_id)
}
pub fn get_project_id_for_task(&self, task_id: u32) -> Option<u32> {
*self.task_id_to_project_id.get(&task_id).unwrap_or(&None)
}
pub fn peek_next_canonical_id(&self) -> u32 {
self.next_canonical_id
}
pub fn peek_next_canonical_project_id(&self) -> u32 {
self.next_canonical_project_id
}
pub fn peek_next_friendly_id_by_project(&self, project_id: u32) -> u32 {
*self
.next_friendly_id_by_project
.get(&project_id)
.unwrap_or(&1)
}
pub fn peek_next_friendly_id_by_default(&self) -> u32 {
self.next_friendly_id_by_default
}
pub fn move_task_to_list(&mut self, task_id: u32, list_name: impl Into<String>) {
self.task_id_to_list_name.insert(task_id, list_name.into());
}
pub fn move_task_to_project(&mut self, task_id: u32, project_id: u32) {
self.task_id_to_project_id.insert(task_id, Some(project_id));
}
pub fn register_list(&mut self, task_list: &TaskList) {
task_list.task_ids.iter().for_each(|task_id| {
self
.task_id_to_list_name
.insert(*task_id, task_list.name.clone());
});
}
pub fn register_project(&mut self, project: &Project) {
self
.project_key_to_canonical_id
.entry(project.key.clone())
.or_default()
.push(project.id);
project.task_ids.iter().for_each(|task_id| {
self
.task_id_to_project_id
.insert(*task_id, Some(project.id));
});
}
pub fn register_task(
&mut self,
task: &Task,
list_name: impl Into<String>,
project_id: Option<u32>,
) {
self
.task_friendly_id_to_canonical_id
.insert(task.friendly_id.clone(), task.id);
self.task_id_to_list_name.insert(task.id, list_name.into());
if let Some(project_id) = project_id {
self.task_id_to_project_id.insert(task.id, Some(project_id));
}
}
pub fn remove_project(&mut self, project: &Project) {
if let Some(ids) = self.project_key_to_canonical_id.get_mut(&project.key) {
ids.retain(|&id| id != project.id);
if ids.is_empty() {
self.project_key_to_canonical_id.remove(&project.key);
}
}
self.next_friendly_id_by_project.remove(&project.id);
self
.task_id_to_project_id
.retain(|_, project_opt| project_opt.is_none_or(|pid| pid != project.id));
}
pub fn remove_task(&mut self, task: &Task) {
self
.task_friendly_id_to_canonical_id
.remove(&task.friendly_id);
self.task_id_to_list_name.remove(&task.id);
self.task_id_to_project_id.remove(&task.id);
}
pub fn remove_task_from_project(&mut self, task_id: u32) {
self.task_id_to_project_id.remove(&task_id);
}
}
impl Default for VaultIndex {
fn default() -> Self {
Self {
next_canonical_id: 1,
next_canonical_project_id: 1,
next_friendly_id_by_project: HashMap::new(),
next_friendly_id_by_default: 1,
project_key_to_canonical_id: HashMap::new(),
task_friendly_id_to_canonical_id: HashMap::new(),
task_id_to_list_name: HashMap::new(),
task_id_to_project_id: HashMap::new(),
}
}
}