use std::io;
use lazy_static::lazy_static;
use regex::Regex;
use serde::Serialize;
use xml_writer::XmlWriter;
use crate::traits::ToXml;
pub struct ExternalReferenceError;
lazy_static! {
static ref URL_REGEX: Regex = Regex::new(r"^([a-z0-9+.-]+):(?://(?:((?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*)@)?((?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*)(?::(\d*))?(/(?:[a-z0-9-._~!$&'()*+,;=:@/]|%[0-9A-F]{2})*)?|(/?(?:[a-z0-9-._~!$&'()*+,;=:@]|%[0-9A-F]{2})+(?:[a-z0-9-._~!$&'()*+,;=:@/]|%[0-9A-F]{2})*)?)(?:\?((?:[a-z0-9-._~!$&'()*+,;=:/?@]|%[0-9A-F]{2})*))?(?:#((?:[a-z0-9-._~!$&'()*+,;=:/?@]|%[0-9A-F]{2})*))?$").expect("Could not compile URL regex");
}
#[derive(Serialize)]
pub struct ExternalReference {
#[serde(rename = "type")]
pub ref_type: String,
pub url: String,
}
impl<'a> ExternalReference {
pub fn new(ref_type: &'a str, url: &'a str) -> Result<Self, ExternalReferenceError> {
if URL_REGEX.is_match(url) {
Ok(Self {
ref_type: ref_type.to_string(),
url: url.to_string(),
})
} else {
Err(ExternalReferenceError)
}
}
}
impl ToXml for ExternalReference {
fn to_xml<W: io::Write>(&self, xml: &mut XmlWriter<W>) -> io::Result<()> {
xml.begin_elem("reference")?;
xml.attr("type", &self.ref_type)?;
xml.begin_elem("url")?;
xml.text(self.url.trim())?;
xml.end_elem()?;
xml.end_elem()
}
}
impl ToXml for Vec<ExternalReference> {
fn to_xml<W: io::Write>(&self, xml: &mut XmlWriter<W>) -> io::Result<()> {
if !self.is_empty() {
xml.begin_elem("externalReferences")?;
for reference in self {
reference.to_xml(xml)?;
}
xml.end_elem()?;
}
Ok(())
}
}