use std::fmt;
use super::super::add_traits::{Trim};
pub struct DotTable {
header: String,
attributes: Vec<(String, String)>,
footer: String,
dark_mode: bool
}
impl fmt::Display for DotTable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{0}\n{1}\n\n\t{2}\n", self.header, self.attributes.clone().into_iter().map(|(_, value)| value).collect::<Vec<String>>().join("\n"), self.footer)
}
}
impl DotTable {
pub fn new(table_name: &str, dark_mode: bool) -> DotTable {
let header : String = generate_table_header(table_name, dark_mode);
DotTable {
header,
attributes: Vec::new(),
footer: String::from("</TABLE> >]"),
dark_mode
}
}
fn index_of_attribute(&mut self, attr_name: &str) -> Result<usize, &'static str> {
let filtered_key_map : Vec<(usize, String)> = self.attributes
.clone()
.into_iter()
.enumerate()
.map(|(i, (key, _))| (i, key))
.filter(|(_, key)| key == attr_name)
.collect();
match filtered_key_map.is_empty() {
true => Err("No such attribute"),
false => Ok(filtered_key_map.first().unwrap().0)
}
}
fn replace_attribute(&mut self, attr_name: &str, new_value: String) -> Result<usize, &'static str> {
match self.index_of_attribute(attr_name) {
Ok(index) => {let _ = std::mem::replace(&mut self.attributes[index], (attr_name.to_string(), new_value)); Ok(index)},
Err(err) => Err(err)
}
}
fn push_or_replace_attribute(&mut self, attr_name: &str, value: String) {
if self.replace_attribute(attr_name, value.clone()).is_err() {
self.attributes.push((attr_name.to_string(), value));
}
}
pub fn add_attribute(&mut self, title: &str, desc : &str) {
self.attributes.push((title.to_string(), generate_attribute(title, desc, self.dark_mode)));
}
pub fn add_attribute_fk(&mut self, key: &str, fk_table : &str, fk_col : &str) {
self.push_or_replace_attribute(key, generate_fk_attribute(key, fk_table, fk_col, self.dark_mode));
}
}
fn generate_table_header(name: &str, dark_mode: bool) -> String {
let styles : (&str, &str) = match dark_mode {
true => ("grey20", "grey10"),
false => ("grey95", "indigo")
};
format!("
{0} [label=<
<TABLE BGCOLOR=\"{1}\" BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\">
<TR><TD COLSPAN=\"2\" CELLPADDING=\"5\" ALIGN=\"CENTER\" BGCOLOR=\"{2}\">
<FONT FACE=\"Roboto\" COLOR=\"white\" POINT-SIZE=\"12\">
<B>{0}</B>
</FONT></TD></TR>", name.trim_leading_trailing(), styles.0, styles.1)
}
fn generate_attribute(title: &str, desc: &str, dark_mode: bool) -> String {
let font_color : &str = match dark_mode {
true => "white",
false => "black"
};
format!("
<TR><TD ALIGN=\"LEFT\" BORDER=\"0\">
<FONT COLOR=\"{0}\" FACE=\"Roboto\"><B>{1}</B></FONT>
</TD><TD ALIGN=\"LEFT\">
<FONT COLOR=\"{0}\" FACE=\"Roboto\">{2}</FONT>
</TD></TR>", font_color, title.trim_leading_trailing(), desc.trim_leading_trailing()
)
}
fn generate_fk_attribute(key: &str, fk_table: &str, fk_col: &str, dark_mode: bool) -> String {
let font_color : &str = match dark_mode {
true => "white",
false => "black"
};
let refer_sign : &str = match cfg!(unix) {
true => "\u{1F5DD}",
_ => "[FK]"
};
format!("
<TR><TD ALIGN=\"LEFT\" BORDER=\"0\">
<FONT COLOR=\"{0}\" FACE=\"Roboto\"><B>{1} {2}</B></FONT>
</TD><TD ALIGN=\"LEFT\">
<FONT FACE=\"Roboto\" COLOR=\"{0}\">Refers to <I>{3}[{4}]</I></FONT>
</TD></TR>", font_color, key.trim_leading_trailing(), refer_sign, fk_table.trim_leading_trailing(), fk_col.trim_leading_trailing()
)
}