use std::fs;
use anyhow::Result;
use csv::{Reader, Writer};
use directories::BaseDirs;
use colored::Colorize;
use crate::{errors::TErrors, todos::Todo, user_input};
pub fn read_from_file() -> Result<Vec<Todo>> {
let path = BaseDirs::new().unwrap().config_dir().join("rtodo/db.json");
let td_str = std::fs::read_to_string(path)?;
let todos: Vec<Todo> = serde_json::from_str(&td_str).map_err(|_| TErrors::ReadFromFile)?;
Ok(todos)
}
pub fn write_to_file(todos: &Vec<Todo>) -> Result<()> {
let path = BaseDirs::new().unwrap().config_dir().join("rtodo");
if !path.exists() {
std::fs::create_dir(&path)?;
}
std::fs::write(path.join("db.json"), serde_json::to_string(&todos)?)
.map_err(|_| TErrors::WriteToFile)?;
Ok(())
}
pub fn import_menu(td: &mut Vec<Todo>) -> Result<()> {
print!("{}", "Format to import: ".magenta());
print!(
"\n{}{} {}{} {}",
"[1]".blue().bold(),
"CSV".white().bold(),
"[2]".blue().bold(),
"JSON".white().bold(),
" -> ".green().bold()
);
let format = user_input()
.map_err(|e| TErrors::ImportMenu(e.to_string()))?
.trim()
.to_string();
if format.contains('1') {
print!("{} {}", "File Name".white().bold(), " -> ".green().bold());
let name = user_input()?.trim().to_string();
import_from_csv(td, &name)?;
} else if format.contains('2') {
print!("{} {}", "File Name".white().bold(), " -> ".green().bold());
let name = user_input()?.trim().to_string();
import_from_json(td, &name)?;
}
Ok(())
}
pub fn export_menu(td: &Vec<Todo>) -> Result<()> {
print!("{}", "Format to export: ".magenta());
print!(
"\n{}{} {}{} {}",
"[1]".blue().bold(),
"CSV".white().bold(),
"[2]".blue().bold(),
"JSON".white().bold(),
" -> ".green().bold()
);
let format = user_input()
.map_err(|e| TErrors::ExportMenu(e.to_string()))?
.trim()
.to_string();
if format.contains('1') {
print!("{} {}", "File Name".white().bold(), " -> ".green().bold());
let name = user_input()?.trim().to_string();
export_to_csv(td, &name)?;
} else if format.contains('2') {
print!("{} {}", "File Name".white().bold(), " -> ".green().bold());
let name = user_input()?.trim().to_string();
export_to_json(td, &name)?;
}
Ok(())
}
pub fn export_to_csv(td: &[Todo], name: &str) -> Result<()> {
let mut cs_writer = Writer::from_path(name).map_err(|_| TErrors::WriteToFile)?;
for t in td {
cs_writer.serialize(t)?;
cs_writer.flush()?;
}
Ok(())
}
fn export_to_json(td: &Vec<Todo>, name: &str) -> Result<()> {
std::fs::write(name, serde_json::to_string_pretty(td)?).map_err(|_| TErrors::WriteToFile)?;
Ok(())
}
fn import_from_json(td: &mut Vec<Todo>, name: &str) -> Result<()> {
let dt = fs::read_to_string(name).map_err(|_| TErrors::ReadFromFile)?;
let rs: Vec<Todo> = serde_json::from_str(&dt)?;
td.extend(rs);
Ok(())
}
pub fn import_from_csv(td: &mut Vec<Todo>, name: &str) -> Result<()> {
let mut read_csv = Reader::from_path(name).map_err(|_| TErrors::WriteToFile)?;
let it = read_csv.deserialize::<Vec<Todo>>();
for t in it {
td.extend(t.unwrap());
}
Ok(())
}