use anyhow::Result;
use handlebars::{Handlebars, RenderErrorReason};
use rand::{seq::IndexedRandom, Rng};
use rust_embed::Embed;
use serde::Serialize;
use crate::{app::Iocaine, gobbledygook::GobbledyGook, wurstsalat_generator_pro::join_words};
#[derive(Embed)]
#[folder = "templates/"]
#[include = "*.hbs"]
struct Asset;
#[derive(Serialize, Debug)]
struct Enumerator<T> {
index: u32,
value: T,
}
#[derive(Serialize, Debug)]
struct Link {
href_words: u32,
title_words: u32,
}
#[derive(Serialize, Debug)]
struct Page<'a> {
pub request_uri: &'a str,
pub paragraphs: Vec<Enumerator<u32>>,
pub links: Vec<Enumerator<Link>>,
}
pub struct AssembledStatisticalSequences;
impl AssembledStatisticalSequences {
pub fn generate(iocaine: &Iocaine, host: &str, path: &str) -> Result<String> {
let initial_seed = &iocaine.config.generator.initial_seed;
let static_seed = format!("{}/{}#{}", host, path, initial_seed);
let markov_gen = |h: &handlebars::Helper,
_: &Handlebars,
_: &handlebars::Context,
_: &mut handlebars::RenderContext,
out: &mut dyn handlebars::Output|
-> handlebars::HelperResult {
let group = h
.param(0)
.ok_or(RenderErrorReason::ParamNotFoundForIndex("group", 0))?
.value()
.as_str()
.ok_or(RenderErrorReason::InvalidParamType("string"))?;
let index = h
.param(1)
.ok_or(RenderErrorReason::ParamNotFoundForIndex("index", 1))?
.value()
.as_i64()
.ok_or(RenderErrorReason::InvalidParamType("i64"))?;
let words = h
.param(2)
.ok_or(RenderErrorReason::ParamNotFoundForIndex("words", 2))?
.value()
.as_i64()
.ok_or(RenderErrorReason::InvalidParamType("i64"))?;
let rng = GobbledyGook::for_url(format!("{}://{}/{}", group, &static_seed, index));
let chain = iocaine.chain.generate(rng).take(words as usize);
out.write(&join_words(chain))?;
Ok(())
};
let href_gen = |h: &handlebars::Helper,
_: &Handlebars,
_: &handlebars::Context,
_: &mut handlebars::RenderContext,
out: &mut dyn handlebars::Output|
-> handlebars::HelperResult {
let group = h
.param(0)
.ok_or(RenderErrorReason::ParamNotFoundForIndex("group", 0))?
.value()
.as_str()
.ok_or(RenderErrorReason::InvalidParamType("string"))?;
let index = h
.param(1)
.ok_or(RenderErrorReason::ParamNotFoundForIndex("index", 1))?
.value()
.as_i64()
.ok_or(RenderErrorReason::InvalidParamType("i64"))?;
let count = h
.param(2)
.ok_or(RenderErrorReason::ParamNotFoundForIndex("count", 2))?
.value()
.as_i64()
.ok_or(RenderErrorReason::InvalidParamType("i64"))?;
let mut rng = GobbledyGook::for_url(format!("{}://{}/{}", group, &static_seed, index));
let words = (1..=count)
.map(|_| iocaine.words.0.choose(&mut rng).unwrap().as_str())
.collect::<Vec<_>>()
.join("-");
out.write(&words)?;
Ok(())
};
let isroot = |_: &handlebars::Helper,
_: &Handlebars,
_: &handlebars::Context,
_: &mut handlebars::RenderContext,
out: &mut dyn handlebars::Output|
-> handlebars::HelperResult {
if path == "/" {
out.write("true")?;
}
Ok(())
};
let mut rng = GobbledyGook::for_url(format!("iocaine://{}", static_seed));
let paragraph_count = rng.random_range(
iocaine.config.generator.markov.paragraphs.min
..=iocaine.config.generator.markov.paragraphs.max,
);
let paragraphs: Vec<Enumerator<u32>> = (0..paragraph_count)
.map(|idx| Enumerator::<u32> {
index: idx,
value: rng.random_range(
iocaine.config.generator.markov.words.min
..=iocaine.config.generator.markov.words.max,
),
})
.collect();
let link_count = rng.random_range(
iocaine.config.generator.links.min..=(iocaine.config.generator.links.max),
);
let links: Vec<Enumerator<Link>> = (0..link_count)
.map(|idx| Enumerator::<Link> {
index: idx,
value: Link {
href_words: rng.random_range(
iocaine.config.generator.links.href_words.min
..=iocaine.config.generator.links.href_words.max,
),
title_words: rng.random_range(
iocaine.config.generator.links.title_words.min
..=iocaine.config.generator.links.title_words.max,
),
},
})
.collect();
let mut handlebars = Handlebars::new();
if let Some(dir) = &iocaine.config.templates.directory {
handlebars
.register_templates_directory(dir, handlebars::DirectorySourceOptions::default())?;
} else {
handlebars.register_embed_templates_with_extension::<Asset>(".hbs")?;
}
handlebars.register_helper("markov-gen", Box::new(markov_gen));
handlebars.register_helper("href-gen", Box::new(href_gen));
handlebars.register_helper("is-root", Box::new(isroot));
let data = Page {
request_uri: path,
paragraphs,
links,
};
let host_template = &format!("hosts/{}", host);
let rendered = if handlebars.has_template(host_template) {
handlebars.render(host_template, &data)?
} else {
handlebars.render("main", &data)?
};
Ok(rendered)
}
}