use crate::type_map::java_type;
use alef_codegen::naming::to_java_name;
use alef_core::hash::{self, CommentStyle};
use alef_core::ir::{ApiSurface, TypeRef};
use std::collections::HashSet;
use std::fmt::Write;
use super::helpers::is_bridge_param_java;
#[allow(clippy::too_many_arguments)]
pub(crate) fn gen_facade_class(
api: &ApiSurface,
package: &str,
public_class: &str,
raw_class: &str,
_prefix: &str,
bridge_param_names: &HashSet<String>,
bridge_type_aliases: &HashSet<String>,
has_visitor_bridge: bool,
) -> String {
let mut body = String::with_capacity(4096);
writeln!(body, "public final class {} {{", public_class).ok();
writeln!(body, " private {}() {{ }}", public_class).ok();
writeln!(body).ok();
for func in &api.functions {
let params: Vec<String> = func
.params
.iter()
.filter(|p| !is_bridge_param_java(p, bridge_param_names, bridge_type_aliases))
.map(|p| {
let ptype = java_type(&p.ty);
format!("final {} {}", ptype, to_java_name(&p.name))
})
.collect();
let return_type = java_type(&func.return_type);
if !func.doc.is_empty() {
writeln!(body, " /**").ok();
for line in func.doc.lines() {
writeln!(body, " * {}", line).ok();
}
writeln!(body, " */").ok();
}
writeln!(
body,
" public static {} {}({}) throws {}Exception {{",
return_type,
to_java_name(&func.name),
params.join(", "),
raw_class
)
.ok();
for param in &func.params {
if !param.optional && !is_bridge_param_java(param, bridge_param_names, bridge_type_aliases) {
let pname = to_java_name(¶m.name);
writeln!(
body,
" java.util.Objects.requireNonNull({}, \"{} must not be null\");",
pname, pname
)
.ok();
}
}
let call_args: Vec<String> = func
.params
.iter()
.filter(|p| !is_bridge_param_java(p, bridge_param_names, bridge_type_aliases))
.map(|p| to_java_name(&p.name))
.collect();
if matches!(func.return_type, TypeRef::Unit) {
writeln!(
body,
" {}.{}({});",
raw_class,
to_java_name(&func.name),
call_args.join(", ")
)
.ok();
} else {
writeln!(
body,
" return {}.{}({});",
raw_class,
to_java_name(&func.name),
call_args.join(", ")
)
.ok();
}
writeln!(body, " }}").ok();
writeln!(body).ok();
let has_optional = func
.params
.iter()
.any(|p| p.optional && !is_bridge_param_java(p, bridge_param_names, bridge_type_aliases));
if has_optional {
let required_params: Vec<String> = func
.params
.iter()
.filter(|p| !p.optional && !is_bridge_param_java(p, bridge_param_names, bridge_type_aliases))
.map(|p| {
let ptype = java_type(&p.ty);
format!("final {} {}", ptype, to_java_name(&p.name))
})
.collect();
writeln!(
body,
" public static {} {}({}) throws {}Exception {{",
return_type,
to_java_name(&func.name),
required_params.join(", "),
raw_class
)
.ok();
let full_args: Vec<String> = func
.params
.iter()
.filter(|p| !is_bridge_param_java(p, bridge_param_names, bridge_type_aliases))
.map(|p| {
if p.optional {
"null".to_string()
} else {
to_java_name(&p.name)
}
})
.collect();
if matches!(func.return_type, TypeRef::Unit) {
writeln!(
body,
" {}.{}({});",
raw_class,
to_java_name(&func.name),
full_args.join(", ")
)
.ok();
} else {
writeln!(
body,
" return {}.{}({});",
raw_class,
to_java_name(&func.name),
full_args.join(", ")
)
.ok();
}
writeln!(body, " }}").ok();
writeln!(body).ok();
}
}
if has_visitor_bridge {
writeln!(body, " /**").ok();
writeln!(
body,
" * Convert HTML to Markdown, invoking visitor callbacks during processing."
)
.ok();
writeln!(body, " */").ok();
writeln!(
body,
" public static ConversionResult convertWithVisitor(String html, ConversionOptions options, Visitor visitor)"
)
.ok();
writeln!(body, " throws {}Exception {{", raw_class).ok();
writeln!(
body,
" return {}.convertWithVisitor(html, options, visitor);",
raw_class
)
.ok();
writeln!(body, " }}").ok();
writeln!(body).ok();
}
writeln!(body, "}}").ok();
let mut out = String::with_capacity(body.len() + 512);
out.push_str(&hash::header(CommentStyle::DoubleSlash));
writeln!(out, "package {};", package).ok();
let has_list = body.contains("List<");
let has_map = body.contains("Map<");
let has_optional = body.contains("Optional<");
let has_imports = has_list || has_map || has_optional;
if has_imports {
writeln!(out).ok();
if has_list {
writeln!(out, "import java.util.List;").ok();
}
if has_map {
writeln!(out, "import java.util.Map;").ok();
}
if has_optional {
writeln!(out, "import java.util.Optional;").ok();
}
}
writeln!(out).ok();
out.push_str(&body);
out
}