use std::marker::PhantomData;
use edifact_rs::Writer;
use crate::{Error, Release};
use super::{Set, Unset, bytes_to_segments};
#[derive(Debug, Clone)]
struct ContrlBuilderInner {
release: Release,
message_ref: String,
interchange_ref: String,
sender_id: Option<String>,
receiver_id: Option<String>,
action_code: String,
syntax_error: Option<String>,
}
#[derive(Debug, Clone)]
#[must_use = "Builder must be consumed via .build() or .serialize()"]
pub struct ContrlBuilder<S = Unset, R = Unset> {
_ph: PhantomData<fn() -> (S, R)>,
inner: ContrlBuilderInner,
}
impl ContrlBuilder<Unset, Unset> {
pub fn new(release: Release) -> Self {
Self {
_ph: PhantomData,
inner: ContrlBuilderInner {
release,
message_ref: "1".to_owned(),
interchange_ref: String::new(),
sender_id: None,
receiver_id: None,
action_code: "7".to_owned(),
syntax_error: None,
},
}
}
}
impl<S, R> ContrlBuilder<S, R> {
pub fn for_interchange(
mut self,
header: &crate::interchange::InterchangeHeader,
) -> ContrlBuilder<Set, Set> {
self.inner.sender_id = Some(header.receiver_id.to_string());
self.inner.receiver_id = Some(header.sender_id.to_string());
self.inner.interchange_ref = header.control_ref.to_string();
self.transition()
}
fn transition<S2, R2>(self) -> ContrlBuilder<S2, R2> {
ContrlBuilder {
_ph: PhantomData,
inner: self.inner,
}
}
pub fn sender(mut self, id: impl Into<String>) -> ContrlBuilder<Set, R> {
self.inner.sender_id = Some(id.into());
self.transition()
}
pub fn receiver(mut self, id: impl Into<String>) -> ContrlBuilder<S, Set> {
self.inner.receiver_id = Some(id.into());
self.transition()
}
pub fn interchange_ref(mut self, reference: impl Into<String>) -> Self {
self.inner.interchange_ref = reference.into();
self
}
pub fn message_ref(mut self, reference: impl Into<String>) -> Self {
self.inner.message_ref = reference.into();
self
}
pub fn accept(mut self) -> Self {
"7".clone_into(&mut self.inner.action_code);
self.inner.syntax_error = None;
self
}
pub fn reject(mut self, syntax_error: impl Into<String>) -> Self {
"4".clone_into(&mut self.inner.action_code);
self.inner.syntax_error = Some(syntax_error.into());
self
}
pub fn action_code(mut self, code: impl Into<String>) -> Self {
self.inner.action_code = code.into();
self
}
fn to_bytes(&self) -> Result<Vec<u8>, Error> {
let sender = self.inner.sender_id.as_deref().unwrap_or("");
let receiver = self.inner.receiver_id.as_deref().unwrap_or("");
let mut buf = Vec::new();
let mut w = Writer::new(&mut buf);
emit_comp!(
w,
"UNH",
[&self.inner.message_ref],
["CONTRL", "D", "3", "UN", self.inner.release.as_str()]
);
if let Some(code) = self.inner.syntax_error.as_deref() {
emit_comp!(
w,
"UCI",
[&self.inner.interchange_ref],
[sender, super::interchange::unb_qualifier(sender)],
[receiver, super::interchange::unb_qualifier(receiver)],
[&self.inner.action_code],
[code]
);
} else {
emit_comp!(
w,
"UCI",
[&self.inner.interchange_ref],
[sender, super::interchange::unb_qualifier(sender)],
[receiver, super::interchange::unb_qualifier(receiver)],
[&self.inner.action_code]
);
}
w.finish_unt(&self.inner.message_ref)
.map_err(Error::Parse)?;
Ok(buf)
}
pub fn serialize(self) -> Result<Vec<u8>, Error> {
self.to_bytes()
}
}
impl ContrlBuilder<Set, Set> {
pub fn build(self) -> Result<crate::messages::contrl::ContrlMessage, Error> {
let message_ref = self.inner.message_ref.clone();
let assoc_code = self.inner.release.as_str().to_owned();
let segments = bytes_to_segments(&self.to_bytes()?)?;
Ok(crate::messages::contrl::ContrlMessage::from_parts(
segments,
message_ref.as_str(),
assoc_code.as_str(),
None, ))
}
}