use std::collections::HashMap;
use time::macros::format_description;
use crate::components::trace::OneTrace;
use regex::Regex;
pub const FORMATTER_VARIABLE: [&str; 8] = ["time","lvl","file","line","msg","thread","context","extra"];
pub type FormaterCompilerSignature = fn(formater: &String) -> FormaterCompiled;
pub type FormaterParamBuilderSignature = fn(&OneTrace, &String) -> HashMap<String, String>;
pub struct FormaterCompiled
{
pub inner: Vec<(String, Option<FormaterData>)>,
}
impl FormaterCompiled
{
pub fn render(&self, parameters: HashMap<String, String>) -> String
{
return self.inner.iter().map(|(previous,data)|{
if let Some(data) = data
{
match parameters.get(&data.data) {
None => {}
Some(content) => {
if(!content.is_empty()) {
return format!("{}{}{}{}", previous, data.prefix, parameters.get(&data.data).unwrap_or(&String::new()), data.suffix);
}
}
}
}
return previous.clone();
}).collect::<Vec<String>>().join("");
}
}
#[derive(Debug)]
pub struct FormaterData {
pub prefix: String,
pub data: String,
pub suffix: String,
}
pub fn FormaterCompile(formater: &String) -> FormaterCompiled
{
let mut compiled = vec![];
let mut lastchar = 0;
let regexstr = format!(r"\{{({})(:([><])([^}}]+))?\}}", FORMATTER_VARIABLE.map(|var|{
if(var=="extra")
{
return r"extra\[([^\]]+)\]";
}
return var;
}).join("|"));
let regex = Regex::new(®exstr).unwrap();
let _ = regex.replace_all(formater, |caps: ®ex::Captures| {
let mut data = caps.get(1).unwrap().as_str().to_string();
let previous = &formater[lastchar..caps.get(0).unwrap().start()];
lastchar = caps.get(0).unwrap().end();
if(data.starts_with("extra"))
{
if let Some(extrakey) = caps.get(2)
{
data=format!("extra:{}",extrakey.as_str());
}
}
let mut prefix = "".to_string();
let mut suffix = "".to_string();
if let Some(indicator) = caps.get(4)
{
if let Some(affix) = caps.get(5)
{
if(indicator.as_str()=="<")
{
prefix = affix.as_str().to_string();
}
else
{
suffix = affix.as_str().to_string();
}
}
}
compiled.push((previous.to_string(), Some(FormaterData{
prefix: prefix,
data,
suffix: suffix,
})));
"".to_string()
}).into_owned();
compiled.push((formater[lastchar..].to_string(), None));
return FormaterCompiled{ inner: compiled };
}
pub fn FormaterParamBuilder(trace: &OneTrace, lineReturn: &String) -> HashMap<String, String>
{
let mut msg = trace.message.clone();
if(msg.contains("\n") || msg.contains("\r") || msg.contains("\\n") || msg.contains("\\r"))
{
let linereturn = format!("\n{}",lineReturn);
msg = msg.replace("\n\r","\n");
msg = msg.replace("\\n\\r","\n");
msg = msg.replace("\r","\n");
msg = msg.replace("\\r","\n");
msg = msg.replace("\\n","\n");
msg = msg.replace("\n",linereturn.as_str());
}
if(trace.backtraces.len()>0)
{
let mut drawBacktraces= "".to_string();
trace.backtraces.iter().for_each(|one|{
drawBacktraces = format!("{}\n{}{}",drawBacktraces,lineReturn,one.to_string());
});
msg = format!("{}, with : {}",msg,drawBacktraces)
}
let mut parameters = HashMap::new();
let formatTime = format_description!("[hour repr:24]:[minute]:[second].[subsecond digits:6]");
parameters.insert("time".to_string(), trace.date.format(formatTime).unwrap_or("00:00:00.000000".to_string()));
parameters.insert("lvl".to_string(), trace.level.convert4LengthString());
parameters.insert("thread".to_string(), trace.context.threadName_get().clone().unwrap_or("".to_string()));
parameters.insert("context".to_string(), trace.context.name_get().clone().unwrap_or("".to_string()));
parameters.insert("file".to_string(), trace.filename.clone());
parameters.insert("line".to_string(), trace.fileline.to_string());
trace.context.extra_getAll().iter().for_each(|(key,data)|{
parameters.insert(format!("extra:{}",key), data.to_string());
});
parameters.insert("msg".to_string(), msg);
return parameters;
}