use crate::{
error::CorrError, ASTElement, FormattedTextBlock, ListItem, ListItemType, TextFormat, AST,
};
use std::fmt::Write;
pub trait RenderHTML {
fn render(input: &Self) -> Result<String, CorrError>;
}
impl RenderHTML for TextFormat {
fn render(input: &Self) -> Result<String, CorrError> {
let mut return_value = String::new();
match input {
Self::Bold(bold_input) => {
write! {return_value, "<b>{}</b>", bold_input
.iter()
.map(Self::render)
.collect::<Result<String, CorrError>>()?}?;
}
Self::StrikeThrough(striketrough_input) => {
write! {return_value, "<s>{}</s>", striketrough_input
.iter()
.map(Self::render)
.collect::<Result<String, CorrError>>()?}?;
}
Self::Italic(italic_input) => {
write! {return_value, "<i>{}</i>", italic_input.iter()
.map(Self::render)
.collect::<Result<String, CorrError>>()?}?;
}
Self::Link { name, href } => {
write! {return_value, "<a href=\" {} \">{}</a>", href, name.iter()
.map(Self::render)
.collect::<Result<String, CorrError>>()?}?;
}
Self::Text(text_input) => {
return_value = text_input.clone();
}
};
Ok(return_value)
}
}
impl RenderHTML for FormattedTextBlock {
fn render(input: &Self) -> Result<String, CorrError> {
input
.inhalt
.iter()
.map(TextFormat::render)
.collect::<Result<String, CorrError>>()
}
}
impl RenderHTML for ASTElement {
fn render(input: &Self) -> Result<String, CorrError> {
let mut output = String::new();
match input {
Self::Heading { text, tier } => {
write! {output, "<h{}>{}</h{}>", tier, FormattedTextBlock::render(text)?, tier}?;
}
Self::TextBlock { text } => {
write! {output, "<p>{}</p>", FormattedTextBlock::render(text)?}?;
}
Self::Image {
link_text,
link_url,
image_alt,
image_url,
} => {
write! {output,
"<a href=\"{}\"><img src=\"{}\" alt=\"{}\">{}</a>",
match link_url {
Some(inhalt) => inhalt,
None => "",
},
image_url ,
match image_alt {
Some(inhalt) => inhalt,
None => "",
},
match link_text {
Some(inhalt) => inhalt,
None => "",
},
}?;
}
Self::Liste { elements } => {
output += "<ul>";
let mut lvl: usize = 0;
for current_element in elements {
while current_element.level != lvl {
if current_element.level > lvl {
output += "<ul>";
lvl = lvl.saturating_add(1);
} else {
output += "</ul>";
lvl = lvl.saturating_sub(1);
}
}
write! {output, "{}", ListItem::render(current_element)?}?
}
while 0 != lvl {
output += "</ul>";
lvl = lvl.saturating_sub(1);
}
output += "</ul>";
}
Self::Table { headers, inhalt } => {
write! {output,
"<table><tr>{}</tr>{}<table>",
headers.iter()
.map(|one_header_element| -> Result<String, CorrError> {Ok(String::from("</th>") + &FormattedTextBlock::render(one_header_element)? + "</th>")})
.collect::<Result<String, CorrError>>()?, Self::render_inhalt_table(inhalt)?
}?;
}
};
Ok(output)
}
}
impl ASTElement {
fn render_inhalt_table(input: &Vec<Vec<FormattedTextBlock>>) -> Result<String, CorrError> {
let mut output = String::new();
for single_row in input {
write! {output,
"<tr>{}<tr>",
single_row.iter()
.map(|parsed| -> Result<String, CorrError> {
let mut one_cell = String::new();
write! {one_cell, "<td>{}</td>", FormattedTextBlock::render(parsed)?}?;
Ok(one_cell)})
.collect::<Result<String, CorrError>>()?}?
}
Ok(output)
}
}
impl RenderHTML for ListItem {
fn render(input: &Self) -> Result<String, CorrError> {
let mut output = String::new();
match input.item_type {
ListItemType::Unordered => {
write! {output, "<li>- {}<li>", FormattedTextBlock::render(&input.content)?}?
}
ListItemType::Ordered(inhalt) => {
write! {output, "<li>{}. {}<li>", inhalt ,FormattedTextBlock::render(&input.content)?}?
}
};
Ok(output)
}
}
impl RenderHTML for AST {
fn render(input: &Self) -> Result<String, CorrError> {
input
.root
.iter()
.map(ASTElement::render)
.collect::<Result<String, CorrError>>()
}
}