1use std::path::Path;
2
3pub mod error;
4pub mod project;
5mod storage;
6pub mod task;
7
8use project::Project;
9use task::Task;
10
11fn list_filter<F>(path: &Path, project: Option<String>, op: F) -> Result<(), error::RustaskError>
12where
13 F: Fn(&usize, &Task) -> bool,
14{
15 let projects = storage::load_tasks(&path)?;
16 match project {
17 None => {
18 let projs = storage::load_tasks(&path)?;
19 for (i, proj) in projs.iter().enumerate() {
20 println!("{}", proj);
21 proj.tasks()
22 .iter()
23 .enumerate()
24 .filter(|(i, t)| op(i, *t))
25 .for_each(|(idx, t)| println!("[{}]: {}", idx, t));
26 if i != projs.len() - 1 {
27 println!("");
28 }
29 }
30 Ok(())
31 }
32 Some(name) => {
33 if let Some(idx) = projects.iter().position(|p| p.name == name) {
34 println!("{}", projects[idx]);
35 projects[idx]
36 .tasks()
37 .iter()
38 .enumerate()
39 .filter(|(i, t)| op(i, *t))
40 .for_each(|(idx, t)| println!("[{}]: {}", idx, t));
41 Ok(())
42 } else {
43 Err(error::RustaskError::ProjectNotFound(name))
44 }
45 }
46 }
47}
48
49pub fn list_all(path: &Path, project: Option<String>) -> Result<(), error::RustaskError> {
51 list_filter(path, project, |_a, _b| true)
52}
53
54pub fn list(path: &Path, project: Option<String>) -> Result<(), error::RustaskError> {
56 list_filter(path, project, |_, t| t.choose())
57}
58
59pub fn rename(path: &Path, project: String, name: String) -> Result<(), error::RustaskError> {
61 let mut projs = storage::load_tasks(&path)?;
62 if let Some(idx) = projs.iter().position(|p| p.name == project) {
63 if projs.iter().any(|p| p.name == name) {
64 return Err(error::RustaskError::ProjectNameTaken(name));
65 }
66 projs[idx].rename(name);
67 } else {
68 return Err(error::RustaskError::ProjectNotFound(project));
69 }
70 storage::store_tasks(&path, &projs)
71}
72
73pub fn add_task(path: &Path, task: Task, name: String) -> Result<(), error::RustaskError> {
75 let mut projs = storage::load_tasks(&path)?;
76 if let Some(idx) = projs.iter().position(|p| p.name == name) {
77 projs[idx].push(task);
78 } else {
79 let mut p = Project::new(name);
80 p.push(task);
81 projs.push(p);
82 projs.sort();
83 }
84
85 storage::store_tasks(&path, &projs)
86}
87
88pub fn remove_task(path: &Path, id: usize, name: String) -> Result<Task, error::RustaskError> {
90 let mut projs = storage::load_tasks(&path)?;
91 let idx_res = projs.iter().position(|p| p.name == name);
92 if idx_res.is_none() {
93 return Err(error::RustaskError::ProjectNotFound(name));
94 }
95
96 let idx = idx_res.unwrap();
97
98 let task = projs[idx].remove(id)?;
99 if projs[idx].len() == 0 {
100 projs.remove(idx);
101 }
102 storage::store_tasks(&path, &projs)?;
103 Ok(task)
104}
105
106pub fn move_task(
107 path: &Path,
108 old_project: String,
109 id: usize,
110 new_project: String,
111) -> Result<(), error::RustaskError> {
112 let task = remove_task(path, id, old_project)?;
113 add_task(path, task, new_project)
114}
115
116pub fn edit_task(
118 path: &Path,
119 id: usize,
120 name: String,
121 description: Option<String>,
122 priority: Option<task::Priority>,
123 deadline: Option<task::Deadline>,
124) -> Result<(), error::RustaskError> {
125 let mut projs = storage::load_tasks(&path)?;
126 let idx_res = projs.iter().position(|p| p.name == name);
127 if idx_res.is_none() {
128 return Err(error::RustaskError::ProjectNotFound(name));
129 }
130
131 let idx = idx_res.unwrap();
132 projs[idx].edit(id, |mut task| {
133 if let Some(d) = description {
134 task.description = d;
135 }
136 if let Some(p) = priority {
137 task.priority = Some(p);
138 }
139 if let Some(d) = deadline {
140 task.deadline = Some(d);
141 }
142 })?;
143 storage::store_tasks(&path, &projs)?;
144 Ok(())
145}