1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use thiserror::Error;

use crate::{compiler::{compilation_result_accessor::CompilationResultAccessor, compilation_error::CompilationError}, resource::ResourceError};

use self::{html_assembler::HtmlAssembler, assembler_configuration::AssemblerConfiguration};

use super::{artifact::{Artifact, ArtifactError}, bibliography::Bibliography, dossier::{Document, Dossier}, output_format::OutputFormat, table_of_contents::TableOfContents};

pub mod html_assembler;
pub mod assembler_configuration;


#[derive(Error, Debug)]
pub enum AssemblerError {
    #[error("too few elements to assemble: {0}")]
    TooFewElements(String),

    #[error(transparent)]
    ArtifactError(#[from] ArtifactError),

    #[error(transparent)]
    CompilationError(#[from] CompilationError),

    #[error("compiled content not found")]
    CompiledContentNotFound,

    #[error(transparent)]
    ResourceError(#[from] ResourceError),
}

pub trait Assembler {

    fn configuration(&self) -> &AssemblerConfiguration;

    fn set_configuration(&mut self, configuration: AssemblerConfiguration);

    fn assemble_dossier(&self, dossier: &Dossier) -> Result<Artifact, AssemblerError>;

    fn assemble_document(&self, document: &Document) -> Result<Artifact, AssemblerError> {

        let mut result = String::new();

        for paragraph in document.preamble() {

            if let Some(r) = paragraph.compilation_result().as_ref() {

                result.push_str(&r.content());

            } else {

                return Err(AssemblerError::CompiledContentNotFound)
            }
        }

        for chapter in document.chapters() {

            if let Some(r) = chapter.heading().compilation_result().as_ref() {

                result.push_str(&r.content());

            } else {

                return Err(AssemblerError::CompiledContentNotFound)
            }

            for paragraph in chapter.paragraphs() {
                if let Some(r) = paragraph.compilation_result().as_ref() {

                    result.push_str(&r.content());
    
                } else {

                    return Err(AssemblerError::CompiledContentNotFound)
                }
            }
        }

        Ok(Artifact::new(result))

    }

    fn assemble_document_standalone(&self, _page_title: &String, _styles_references: Option<&Vec<String>>, toc: Option<&TableOfContents>, bibliography: Option<&Bibliography>, document: &Document) -> Result<Artifact, AssemblerError> {
        self.assemble_document(document)
    }
}

pub fn from(format: OutputFormat, configuration: AssemblerConfiguration) -> Box<dyn Assembler> {
    match format {
        OutputFormat::Html => Box::new(HtmlAssembler::new(configuration))  
    }
}