use crate::emotional_depth::{EmotionalDepthAnalyzer, DirectoryEmotion};
use crate::formatters::{Formatter, PathDisplayMode};
use crate::scanner::{FileNode, TreeStats};
use colored::*;
use std::io::{self, Write};
use std::path::Path;
pub struct EmotionalFormatter {
analyzer: EmotionalDepthAnalyzer,
path_mode: PathDisplayMode,
use_color: bool,
current_depth: usize,
}
impl EmotionalFormatter {
pub fn new(aggression: i32, path_mode: PathDisplayMode, use_color: bool) -> Self {
Self {
analyzer: EmotionalDepthAnalyzer::new(aggression),
path_mode,
use_color,
current_depth: 0,
}
}
fn format_emotion(&self, emotion: DirectoryEmotion) -> String {
if self.use_color {
match emotion {
DirectoryEmotion::Excited => format!("{}", emotion.emoji().bright_yellow()),
DirectoryEmotion::Interested => format!("{}", emotion.emoji().bright_green()),
DirectoryEmotion::Curious => format!("{}", emotion.emoji().cyan()),
DirectoryEmotion::Neutral => format!("{}", emotion.emoji().white()),
DirectoryEmotion::Bored => format!("{}", emotion.emoji().dimmed()),
DirectoryEmotion::Overwhelmed => format!("{}", emotion.emoji().bright_red()),
DirectoryEmotion::Anxious => format!("{}", emotion.emoji().yellow()),
}
} else {
emotion.emoji().to_string()
}
}
fn write_node<W: Write>(
&mut self,
writer: &mut W,
node: &FileNode,
prefix: &str,
is_last: bool,
depth: usize,
) -> io::Result<()> {
self.current_depth = depth;
let should_explore = if node.is_directory {
let emotion = self.analyzer.analyze_directory(
Path::new(&node.name),
&node.children
);
let effective_depth = self.analyzer.calculate_depth(
Path::new(&node.name),
&node.children,
depth
);
let emotion_str = self.format_emotion(emotion);
let branch = if is_last { "└── " } else { "├── " };
let name = if self.use_color {
if node.accessible {
node.name.bright_blue().to_string()
} else {
format!("{} {}", node.name.red(), "(permission denied)".dimmed())
}
} else {
if node.accessible {
node.name.clone()
} else {
format!("{} (permission denied)", node.name)
}
};
writeln!(
writer,
"{}{}{} {} {}",
prefix,
branch,
emotion_str,
name,
if depth < effective_depth {
if self.use_color {
format!("({})", emotion.comment()).dimmed().to_string()
} else {
format!("({})", emotion.comment())
}
} else {
if self.use_color {
"(stopping here...)".dimmed().to_string()
} else {
"(stopping here...)".to_string()
}
}
)?;
depth < effective_depth
} else {
let branch = if is_last { "└── " } else { "├── " };
let name = if self.use_color {
node.name.white().to_string()
} else {
node.name.clone()
};
writeln!(writer, "{}{}{}", prefix, branch, name)?;
false
};
if should_explore && !node.children.is_empty() {
let extension = if is_last { " " } else { "│ " };
let new_prefix = format!("{}{}", prefix, extension);
let last_idx = node.children.len() - 1;
for (idx, child) in node.children.iter().enumerate() {
self.write_node(writer, child, &new_prefix, idx == last_idx, depth + 1)?;
}
}
Ok(())
}
}
impl Formatter for EmotionalFormatter {
fn format(&mut self, root: &FileNode, stats: &TreeStats) -> Vec<u8> {
let mut output = Vec::new();
writeln!(
&mut output,
"🎭 Emotional Tree Explorer - {}\n",
self.analyzer.get_emotional_status()
).unwrap();
writeln!(&mut output, "{}", root.name).unwrap();
if !root.children.is_empty() {
let last_idx = root.children.len() - 1;
for (idx, child) in root.children.iter().enumerate() {
self.write_node(&mut output, child, "", idx == last_idx, 1).unwrap();
}
}
writeln!(&mut output, "\n{}", self.analyzer.emotional_journey_summary()).unwrap();
writeln!(
&mut output,
"\n{} directories, {} files, {} total",
stats.directories,
stats.files,
humansize::format_size(stats.total_size, humansize::DECIMAL)
).unwrap();
output
}
}