use anyhow::{Context, Result};
use std::fs::{File, OpenOptions};
use std::io;
use std::io::{BufRead, BufReader, Write};
use std::str::FromStr;
use crate::data::activity;
#[derive(Debug)]
pub enum LineStatus {
Unchanged,
Changed,
}
#[derive(Debug)]
pub struct Line {
pub plaintext: Option<String>,
pub line_number: Option<usize>,
pub activity: Result<activity::Activity, activity::ActivityError>,
status: LineStatus,
}
impl Line {
#[must_use]
pub fn new(plaintext: &str, line_number: usize) -> Self {
Self {
plaintext: Some(plaintext.trim().to_string()),
line_number: Some(line_number),
activity: activity::Activity::from_str(plaintext),
status: LineStatus::Unchanged,
}
}
#[must_use]
pub fn for_activity(activity: activity::Activity) -> Self {
Self {
plaintext: None,
line_number: None,
activity: Ok(activity),
status: LineStatus::Changed,
}
}
pub fn set_changed(&mut self) {
self.status = LineStatus::Changed;
}
}
pub fn get_file_content(file_name: &str) -> Result<Vec<Line>> {
let file_handler =
File::open(file_name).context(format!("Could not read from file: {file_name}"))?;
let reader = BufReader::new(file_handler);
let lines = reader
.lines()
.map_while(Result::ok)
.enumerate()
.map(|(line_number, line)| Line::new(&line, line_number.saturating_add(1)))
.collect();
Ok(lines)
}
pub fn write_to_file(file_name: &str, file_content: &[Line]) -> Result<(), io::Error> {
let file_handler = get_bartib_file_writable(file_name)?;
for line in file_content {
match &line.status {
LineStatus::Unchanged => {
if let Some(plaintext) = &line.plaintext {
writeln!(&file_handler, "{plaintext}")?
} else {
write!(&file_handler, "{}", line.activity.as_ref().unwrap())?
}
}
LineStatus::Changed => write!(&file_handler, "{}", line.activity.as_ref().unwrap())?,
}
}
Ok(())
}
fn get_bartib_file_writable(file_name: &str) -> Result<File, io::Error> {
OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(file_name)
}