use crate::error::SmoothError;
use crate::libreoffice::LibreOffice;
use crate::metadata::Metadata;
use crate::pandoc::Pandoc;
use crate::tera::Template;
use crate::util;
use crate::OutputFormat;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use tempfile::NamedTempFile;
pub struct File {
path: PathBuf,
output_path: PathBuf,
output_format: OutputFormat,
}
impl<'a> File {
pub fn new<S: Into<&'a str>>(
path: S,
output_path: Option<S>,
output_format: OutputFormat,
) -> Result<Self, SmoothError<'a>> {
let in_path = path.into();
let norm_in_path = util::normalize_path(in_path, None)?;
if !norm_in_path.exists() {
return Err(SmoothError::InputFileNotFound(in_path, norm_in_path));
}
Ok(Self {
path: norm_in_path.clone(),
output_path: match output_path {
Some(x) => util::normalize_path(x.into(), None)?,
None => File::out_path_from_input(norm_in_path, &output_format),
},
output_format: output_format,
})
}
pub fn convert(self, output_raw: bool) -> Result<(), SmoothError<'a>> {
let metadata = Metadata::from(&self.path, &self.parent_folder()?, &self.output_format)?;
let mut content = self.read_source()?;
if metadata.do_tera {
content = Template::new(&self.path, metadata.clone().tera_context)?.apply(content)?;
}
let mut current = File::new_named_tempfile()?;
match current.write_all(content.as_bytes()) {
Ok(_) => {}
Err(e) => return Err(SmoothError::WriteFailed(current.path().to_path_buf(), e)),
};
let prepared_input = current.path().to_path_buf();
if output_raw {
println!("{}", content)
}
let result = match self.output_format {
OutputFormat::Pdf => Pandoc::new().convert_with_metadata_to_pdf(
&prepared_input,
metadata,
&self.output_path,
Some(&self.parent_folder()?),
),
OutputFormat::Odt | OutputFormat::Docx | OutputFormat::OdtPdf => Pandoc::new()
.convert_with_metadata_to_office(
&prepared_input,
metadata,
&self.output_path,
Some(&self.parent_folder()?),
),
OutputFormat::Reveal => Pandoc::new().convert_with_metadata_to_reveal(
&prepared_input,
metadata,
&self.output_path,
Some(&self.parent_folder()?),
),
};
match result {
Ok(_) => (),
Err(e) => return Err(SmoothError::Pandoc(e)),
}
if let OutputFormat::OdtPdf = self.output_format {
let office = LibreOffice::new();
match office.convert_to_pdf(&self.output_path) {
Ok(_) => (),
Err(e) => return Err(SmoothError::LibreOffice(e)),
}
}
Ok(())
}
fn read_source(&self) -> Result<String, SmoothError<'a>> {
match fs::read_to_string(self.path.clone()) {
Ok(x) => Ok(x),
Err(e) => Err(SmoothError::ReadSourceFailed(self.path.clone(), e)),
}
}
fn parent_folder(&self) -> Result<PathBuf, SmoothError<'a>> {
match self.path.parent() {
Some(x) => Ok(x.to_path_buf()),
None => Err(SmoothError::NoParentFolder(self.path.to_path_buf()).into()),
}
}
fn out_path_from_input(input: PathBuf, format: &OutputFormat) -> PathBuf {
match format {
OutputFormat::Pdf => input.with_extension("pdf"),
OutputFormat::Odt | OutputFormat::OdtPdf => input.with_extension("odt"),
OutputFormat::Docx => input.with_extension("docx"),
OutputFormat::Reveal => input.with_extension("html"),
}
}
fn new_named_tempfile() -> Result<NamedTempFile, SmoothError<'a>> {
match NamedTempFile::new() {
Ok(x) => Ok(x),
Err(e) => Err(SmoothError::TemporaryFile(e)),
}
}
}