use serde_derive::{Deserialize, Serialize};
use std::fmt::Display;
use crate::{DatatypeId, NodeType, PropertyId, ShapeId, ValueConstraint};
#[derive(Deserialize, Serialize, Debug, PartialEq, Default, Clone)]
pub struct TapStatement {
#[serde(rename = "propertyID")]
property_id: PropertyId,
#[serde(rename = "propertyLabel", skip_serializing_if = "Option::is_none")]
property_label: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
mandatory: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
repeatable: Option<bool>,
#[serde(rename = "valueNodeType", skip_serializing_if = "Option::is_none")]
value_nodetype: Option<NodeType>,
#[serde(rename = "valueDataType", skip_serializing_if = "Option::is_none")]
value_datatype: Option<DatatypeId>,
#[serde(rename = "valueConstraint", skip_serializing_if = "Option::is_none")]
value_constraint: Option<ValueConstraint>,
#[serde(rename = "valueShape", skip_serializing_if = "Option::is_none")]
value_shape: Option<ShapeId>,
#[serde(rename = "note", skip_serializing_if = "Option::is_none")]
note: Option<String>,
#[serde(skip)]
source_line_number: Option<u64>,
}
impl TapStatement {
pub fn new(property_id: PropertyId) -> TapStatement {
TapStatement::default().with_property_id(property_id)
}
pub fn with_source_line_number(mut self, line: u64) -> Self {
self.source_line_number = Some(line);
self
}
pub fn source_line_number(&self) -> u64 {
self.source_line_number.unwrap_or_default()
}
pub fn with_property_id(mut self, property_id: PropertyId) -> Self {
self.property_id = property_id;
self
}
pub fn set_repeatable(&mut self, repeatable: bool) {
self.repeatable = Some(repeatable);
}
pub fn set_mandatory(&mut self, mandatory: bool) {
self.mandatory = Some(mandatory);
}
pub fn set_value_datatype(&mut self, datatype: &DatatypeId) {
self.value_datatype = Some(datatype.clone());
}
pub fn set_value_nodetype(&mut self, nodetype: &NodeType) {
self.value_nodetype = Some(nodetype.clone());
}
pub fn set_value_shape(&mut self, value_shape: &ShapeId) {
self.value_shape = Some(value_shape.clone());
}
pub fn set_value_constraint(&mut self, value_constraint: &ValueConstraint) {
self.value_constraint = Some(value_constraint.clone());
}
pub fn set_property_label(&mut self, property_label: &str) {
self.property_label = Some(property_label.to_string());
}
pub fn set_note(&mut self, note: &str) {
self.note = Some(note.to_string());
}
pub fn property_id(&self) -> PropertyId {
self.property_id.clone()
}
pub fn mandatory(&self) -> Option<bool> {
self.mandatory
}
pub fn repeatable(&self) -> Option<bool> {
self.repeatable
}
pub fn value_datatype(&self) -> Option<DatatypeId> {
self.value_datatype.clone()
}
pub fn value_shape(&self) -> Option<ShapeId> {
self.value_shape.clone()
}
pub fn value_constraint(&self) -> &Option<ValueConstraint> {
&self.value_constraint
}
pub fn property_label(&self) -> &Option<String> {
&self.property_label
}
}
impl Display for TapStatement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} {}{}{}",
show_property(&self.property_id, &self.property_label),
show_node_constraints(
&self.value_nodetype,
&self.value_datatype,
&self.value_constraint,
&self.value_shape
),
show_cardinality(self.mandatory, self.repeatable),
show_note(&self.note)
)?;
Ok(())
}
}
fn show_property(property_id: &PropertyId, property_label: &Option<String>) -> String {
let mut result = String::new();
if let Some(label) = property_label {
result.push_str(format!("{label} ({property_id})").as_str());
} else {
result.push_str(format!("{property_id}").as_str());
}
result
}
fn show_node_constraints(
value_node_type: &Option<NodeType>,
datatype: &Option<DatatypeId>,
value_constraint: &Option<ValueConstraint>,
value_shape: &Option<ShapeId>,
) -> String {
let mut result = String::new();
if let Some(node_type) = value_node_type {
result.push_str(format!("{node_type} ").as_str());
}
if let Some(datatype) = datatype {
result.push_str(format!("{datatype} ").as_str());
}
if let Some(value_constraint) = value_constraint {
result.push_str(format!("{value_constraint}").as_str());
}
if let Some(value_shape) = value_shape {
result.push_str(format!("@{value_shape} ").as_str());
}
if result.is_empty() {
result.push('.')
}
result
}
fn show_cardinality(mandatory: Option<bool>, repeatable: Option<bool>) -> String {
let mandatory = mandatory.unwrap_or(false);
let repeatable = repeatable.unwrap_or(false);
match (mandatory, repeatable) {
(false, false) => "?".to_string(),
(false, true) => "*".to_string(),
(true, false) => "".to_string(),
(true, true) => "+".to_string(),
}
}
fn show_note(note: &Option<String>) -> String {
if let Some(note) = note {
format!(" // {note}")
} else {
"".to_string()
}
}