use crate::{cli::SortDirection, data::SchoenerIndexes, Error, Result};
use csv::{Terminator, WriterBuilder};
use prettytable::{
format::{FormatBuilder, LinePosition, LineSeparator},
Table,
};
use std::{fs::OpenOptions, io, path::PathBuf};
pub const OUTPUT_HEADERS: [&str; 3] = ["FIRST SPECIES", "SECOND SPECIES", "D INDEX"];
pub enum OutputFormat {
Csv {
path: Option<PathBuf>,
delimiter: Option<char>,
terminator: Option<char>,
quote: Option<char>,
},
Table,
}
pub struct Output {
headers: bool,
sort: Option<SortDirection>,
format: OutputFormat,
}
impl Output {
pub fn new(headers: bool, sort: Option<SortDirection>, format: OutputFormat) -> Self {
Output {
headers,
sort,
format,
}
}
pub fn finalize(self, mut schoener_indexes: SchoenerIndexes) -> Result<()> {
if let Some(direction) = self.sort {
schoener_indexes.sort(direction);
}
match self.format {
OutputFormat::Csv {
path,
delimiter,
terminator,
quote,
} => {
let mut builder = WriterBuilder::new();
if let Some(delimiter) = delimiter {
builder.delimiter(delimiter as u8);
}
if let Some(terminator) = terminator {
builder.terminator(Terminator::Any(terminator as u8));
}
if let Some(quote) = quote {
builder.quote(quote as u8);
}
match path {
Some(path) => {
let file = OpenOptions::new()
.write(true)
.create_new(true)
.open(&path)
.map_err(|error| Error::OutputFile {
path: path.clone(),
error,
})?;
let writer = builder.from_writer(file);
schoener_indexes.output_csv(writer, self.headers)?;
Ok(())
}
None => {
let writer = builder.from_writer(io::stdout());
schoener_indexes.output_csv(writer, self.headers)?;
Ok(())
}
}
}
OutputFormat::Table => {
let mut table = Table::new();
let format = FormatBuilder::new()
.column_separator('│')
.borders('│')
.separators(&[LinePosition::Top], LineSeparator::new('─', '┬', '┌', '┐'))
.separators(
&[LinePosition::Intern],
LineSeparator::new('─', '┼', '├', '┤'),
)
.separators(
&[LinePosition::Bottom],
LineSeparator::new('─', '┴', '└', '┘'),
)
.padding(1, 1)
.build();
table.set_format(format);
schoener_indexes.output_table(table, self.headers)?;
Ok(())
}
}
}
}