use uuid::Uuid;
use std::collections::{HashMap};
use chrono::prelude::*;
#[derive(PartialEq, Debug)]
pub enum RecurState {
Dead,
Active
}
pub trait Recur {
fn current(&self) -> Option<DateTime<Local>>;
fn next(&mut self) -> ();
fn active(&self) -> RecurState;
}
pub trait Dependency {
fn available(&self, space: &Workspace, task: &Task) -> Result<bool, TaskError>;
}
pub struct Task {
pub title: String,
pub date: Box<dyn Recur>,
pub dependencies: Vec<Box<dyn Dependency>>,
pub children: Vec<Uuid>,
pub metadata: HashMap<String, String>,
}
pub struct Workspace {
pub tasks: HashMap<Uuid, Task>,
}
#[derive(Debug)]
pub enum TaskError {
NonexistentError,
NonexistentKeyError,
DuplicateError,
}
impl std::fmt::Display for TaskError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
TaskError::DuplicateError => write!(f, "Task already inserted"),
TaskError::NonexistentError => write!(f, "Task doesn't exist"),
TaskError::NonexistentKeyError => write!(f, "Metadata key doesn't exist"),
}
}
}
impl std::error::Error for TaskError {}
impl Workspace {
pub fn new() -> Workspace {
Workspace {tasks: HashMap::new()}
}
pub fn add_task(&mut self, title: &str, date: Box<dyn Recur>, deps: Vec<Box<dyn Dependency>>) -> Uuid {
let id = Uuid::new_v4();
self.tasks.insert(id, Task {
title: String::from(title),
date,
children: Vec::new(),
metadata: HashMap::new(),
dependencies: deps,
});
id
}
pub fn task_available(&self, id: Uuid) -> Result<bool, TaskError> {
let task = self.tasks.get(&id).ok_or(TaskError::NonexistentError)?;
for dependency in &task.dependencies {
if !dependency.available(&self, task)? {
return Ok(false);
}
}
Ok(true)
}
pub fn task_complete(&mut self, id: Uuid) -> Result<(), TaskError> {
let task = self.tasks.get_mut(&id).ok_or(TaskError::NonexistentError)?;
task.date.next();
Ok(())
}
pub fn task_add_child(&mut self, parent_id: Uuid, child_id: Uuid) -> Result<(), TaskError> {
self.tasks.get(&child_id).ok_or(TaskError::NonexistentError)?;
let task = self.tasks.get_mut(&parent_id).ok_or(TaskError::NonexistentError)?;
for child in &task.children {
if *child == child_id { return Err(TaskError::DuplicateError) }
}
task.children.push(child_id);
Ok(())
}
pub fn task_add_metadata(&mut self, id: Uuid, key: String, val: String) -> Result<(), TaskError> {
let task = self.tasks.get_mut(&id).ok_or(TaskError::NonexistentError)?;
task.metadata.insert(key, val);
Ok(())
}
pub fn task_get_metadata(&mut self, id: Uuid, key: String) -> Result<Option<&String>, TaskError> {
let task = self.tasks.get_mut(&id).ok_or(TaskError::NonexistentError)?;
Ok(task.metadata.get(&key))
}
pub fn task_set_metadata(&mut self, id: Uuid, key: String, val: String) -> Result<(), TaskError> {
let task = self.tasks.get_mut(&id).ok_or(TaskError::NonexistentError)?;
let metadata = task.metadata.get_mut(&key).ok_or(TaskError::NonexistentKeyError)?;
*metadata = val;
Ok(())
}
}