use std::collections::HashMap;
use super::TaskManager;
use super::time_tracking::{TaskStats, TaskTimeInfo, TimeStats};
use brainwires_core::{Task, TaskPriority, TaskStatus};
impl TaskManager {
pub async fn get_ready_tasks(&self) -> Vec<Task> {
let tasks = self.tasks.read().await;
let mut ready = Vec::new();
for task in tasks.values() {
if task.status == TaskStatus::Pending || task.status == TaskStatus::Blocked {
let deps_complete = task.depends_on.iter().all(|dep_id| {
tasks
.get(dep_id)
.map(|t| {
t.status == TaskStatus::Completed || t.status == TaskStatus::Skipped
})
.unwrap_or(false)
});
if deps_complete {
ready.push(task.clone());
}
}
}
ready.sort_by(|a, b| b.priority.cmp(&a.priority));
ready
}
pub async fn get_root_tasks(&self) -> Vec<Task> {
let tasks = self.tasks.read().await;
tasks.values().filter(|t| t.is_root()).cloned().collect()
}
pub async fn get_task_tree(&self, root_id: Option<&str>) -> Vec<Task> {
let tasks = self.tasks.read().await;
let mut result = Vec::new();
match root_id {
Some(id) => {
if let Some(task) = tasks.get(id) {
Self::collect_tree_recursive(&tasks, task, &mut result);
}
}
None => {
for task in tasks.values().filter(|t| t.is_root()) {
Self::collect_tree_recursive(&tasks, task, &mut result);
}
}
}
result
}
fn collect_tree_recursive(tasks: &HashMap<String, Task>, task: &Task, result: &mut Vec<Task>) {
result.push(task.clone());
for child_id in &task.children {
if let Some(child) = tasks.get(child_id) {
Self::collect_tree_recursive(tasks, child, result);
}
}
}
pub async fn get_all_tasks(&self) -> Vec<Task> {
let tasks = self.tasks.read().await;
tasks.values().cloned().collect()
}
pub async fn get_tasks_by_status(&self, status: TaskStatus) -> Vec<Task> {
let tasks = self.tasks.read().await;
tasks
.values()
.filter(|t| t.status == status)
.cloned()
.collect()
}
pub async fn get_stats(&self) -> TaskStats {
let tasks = self.tasks.read().await;
let mut stats = TaskStats::default();
for task in tasks.values() {
stats.total += 1;
match task.status {
TaskStatus::Pending => stats.pending += 1,
TaskStatus::InProgress => stats.in_progress += 1,
TaskStatus::Completed => stats.completed += 1,
TaskStatus::Failed => stats.failed += 1,
TaskStatus::Blocked => stats.blocked += 1,
TaskStatus::Skipped => stats.skipped += 1,
}
}
stats
}
pub async fn get_task_time_info(&self, task_id: &str) -> Option<TaskTimeInfo> {
let tasks = self.tasks.read().await;
tasks.get(task_id).map(|task| TaskTimeInfo {
task_id: task.id.clone(),
description: task.description.clone(),
status: task.status.clone(),
started_at: task.started_at,
completed_at: task.completed_at,
duration_secs: task.duration_secs(),
elapsed_secs: task.elapsed_secs(),
})
}
pub async fn get_time_stats(&self) -> TimeStats {
let tasks = self.tasks.read().await;
let mut total_duration: i64 = 0;
let mut completed_count: usize = 0;
let mut total_elapsed: i64 = 0;
let mut in_progress_count: usize = 0;
for task in tasks.values() {
if let Some(duration) = task.duration_secs() {
total_duration += duration;
completed_count += 1;
}
if task.status == TaskStatus::InProgress
&& let Some(elapsed) = task.elapsed_secs()
{
total_elapsed += elapsed;
in_progress_count += 1;
}
}
TimeStats {
total_duration_secs: total_duration,
completed_tasks: completed_count,
average_duration_secs: if completed_count > 0 {
Some(total_duration / completed_count as i64)
} else {
None
},
current_elapsed_secs: total_elapsed,
in_progress_tasks: in_progress_count,
}
}
pub async fn get_progress(&self, task_id: &str) -> f64 {
let tasks = self.tasks.read().await;
if let Some(task) = tasks.get(task_id) {
if task.children.is_empty() {
match task.status {
TaskStatus::Completed => 1.0,
TaskStatus::InProgress => 0.5,
_ => 0.0,
}
} else {
let completed = task
.children
.iter()
.filter(|id| {
tasks
.get(*id)
.map(|t| t.status == TaskStatus::Completed)
.unwrap_or(false)
})
.count();
let in_progress = task
.children
.iter()
.filter(|id| {
tasks
.get(*id)
.map(|t| t.status == TaskStatus::InProgress)
.unwrap_or(false)
})
.count();
let total = task.children.len() as f64;
if total == 0.0 {
return 0.0;
}
(completed as f64 + (in_progress as f64 * 0.5)) / total
}
} else {
0.0
}
}
pub async fn get_overall_progress(&self) -> f64 {
let stats = self.get_stats().await;
if stats.total == 0 {
return 0.0;
}
let completed = stats.completed as f64;
let in_progress = stats.in_progress as f64 * 0.5;
let total = stats.total as f64;
(completed + in_progress) / total
}
pub async fn get_average_duration(&self) -> Option<i64> {
let tasks = self.tasks.read().await;
let durations: Vec<i64> = tasks.values().filter_map(|t| t.duration_secs()).collect();
if durations.is_empty() {
None
} else {
Some(durations.iter().sum::<i64>() / durations.len() as i64)
}
}
pub async fn estimate_remaining_time(&self) -> Option<i64> {
let avg_duration = self.get_average_duration().await?;
let stats = self.get_stats().await;
let remaining = stats.pending + stats.blocked;
Some(avg_duration * remaining as i64)
}
pub async fn format_tree(&self) -> String {
let tasks = self.tasks.read().await;
let mut output = String::new();
let mut roots: Vec<_> = tasks.values().filter(|t| t.is_root()).collect();
roots.sort_by(|a, b| b.priority.cmp(&a.priority));
let root_count = roots.len();
for (idx, root) in roots.iter().enumerate() {
let is_last = idx == root_count - 1;
Self::format_task_recursive(&tasks, root, 0, is_last, "", &mut output);
}
if output.is_empty() {
output = "No tasks".to_string();
}
output
}
fn format_task_recursive(
tasks: &HashMap<String, Task>,
task: &Task,
depth: usize,
is_last: bool,
parent_prefix: &str,
output: &mut String,
) {
let status_icon = match task.status {
TaskStatus::Pending => "○",
TaskStatus::InProgress => "◐",
TaskStatus::Completed => "●",
TaskStatus::Failed => "✗",
TaskStatus::Blocked => "◌",
TaskStatus::Skipped => "⊘",
};
let priority_icon = match task.priority {
TaskPriority::Urgent => "🔴 ",
TaskPriority::High => "🟠 ",
TaskPriority::Normal => "",
TaskPriority::Low => "🔵 ",
};
let current_prefix = if depth == 0 {
String::new()
} else if is_last {
format!("{}└── ", parent_prefix)
} else {
format!("{}├── ", parent_prefix)
};
output.push_str(&format!(
"{}{} {}{}\n",
current_prefix, status_icon, priority_icon, task.description
));
let child_prefix = if depth == 0 {
String::new()
} else if is_last {
format!("{} ", parent_prefix)
} else {
format!("{}│ ", parent_prefix)
};
let child_count = task.children.len();
for (idx, child_id) in task.children.iter().enumerate() {
if let Some(child) = tasks.get(child_id) {
let child_is_last = idx == child_count - 1;
Self::format_task_recursive(
tasks,
child,
depth + 1,
child_is_last,
&child_prefix,
output,
);
}
}
}
}