use std::{
collections::HashMap,
fs,
path::{Path, PathBuf},
};
use crate::line::{Line, LineSchema};
use std::collections::hash_map::Entry::{Occupied, Vacant};
pub trait LineWriter {
fn write_line(&mut self, line: &Line) -> std::io::Result<()>;
}
pub trait FileLineWriter: LineWriter {
fn file_name(form_name: String) -> String;
fn new(path: &Path, schema: &LineSchema) -> std::io::Result<Box<Self>>;
fn norm_form_name(name: &str) -> String {
name.replace("/", "-")
}
}
pub struct MultiFileLineWriter<T: FileLineWriter> {
base_path: PathBuf,
writers: HashMap<LineSchema, T>,
}
impl<T: FileLineWriter> MultiFileLineWriter<T> {
pub fn new(base_path: PathBuf) -> Self {
Self {
base_path: base_path,
writers: HashMap::new(),
}
}
fn get_form_writer(&mut self, schema: &LineSchema) -> std::io::Result<&mut T> {
Ok(match self.writers.entry(schema.clone()) {
Occupied(e) => e.into_mut(),
Vacant(e) => e.insert(*Self::new_writer(&self.base_path, schema)?),
})
}
fn new_writer(base_path: &PathBuf, schema: &LineSchema) -> std::io::Result<Box<T>> {
let form_name = T::norm_form_name(&schema.code);
let file_name = T::file_name(form_name);
let path = base_path.join(file_name);
fs::create_dir_all(&base_path)?;
log::debug!("Creating new FileLineWriter at: {:?}", path);
let result = T::new(&path, schema)?;
Ok(result)
}
}
impl<T: FileLineWriter> LineWriter for MultiFileLineWriter<T> {
fn write_line(&mut self, line: &Line) -> std::io::Result<()> {
let writer = self.get_form_writer(&line.schema)?;
writer.write_line(line)
}
}