use hard_xml::XmlError;
use hard_xml::XmlRead;
use heck::ToPascalCase;
use rust_decimal::Decimal;
use std::borrow::Cow;
use std::str::FromStr;
use syn::parse_str;
use syn::Ident;
use syn::Type;
use syn::TypePath;

#[derive(Debug, XmlRead)]
#[xml(
    strict(unknown_attribute, unknown_element),
    tag = "businessProcessCatalogue"
)]
pub struct BusinessProcessCatalogue<'a> {
    #[xml(child = "topLevelCatalogueEntry")]
    pub entries: Vec<TopLevelCatalogueEntry<'a>>,

    #[xml(attr = "xmi:id")]
    pub id: Cow<'a, str>,
}

#[derive(Debug, XmlRead)]
#[xml(strict(unknown_attribute, unknown_element), tag = "businessRole")]
pub struct BusinessRole<'a> {
    #[xml(attr = "definition")]
    pub definition: Option<Cow<'a, str>>,

    #[xml(attr = "xmi:id")]
    pub id: Cow<'a, str>,

    #[xml(attr = "name")]
    pub name: Cow<'a, str>,

    #[xml(attr = "registrationStatus")]
    pub registration_status: RegistrationStatus,

    #[xml(child = "semanticMarkup")]
    pub semantic_markup: Vec<SemanticMarkup<'a>>,
}

#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum CatalogueEntryType {
    BusinessArea,
    BusinessProcess,
    MessageSet,
}

impl FromStr for CatalogueEntryType {
    type Err = hard_xml::XmlError;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        match value {
            "iso20022:BusinessArea" => Ok(Self::BusinessArea),
            "iso20022:BusinessProcess" => Ok(Self::BusinessProcess),
            "iso20022:MessageSet" => Ok(Self::MessageSet),
            _ => Err(XmlError::UnrecognizedSymbol {
                symbol: value.into(),
            }),
        }
    }
}

#[derive(Debug, XmlRead)]
#[xml(strict(unknown_attribute, unknown_element), tag = "code")]
pub struct Code<'a> {
    #[xml(attr = "codeName")]
    pub code_name: Option<Cow<'a, str>>,

    #[xml(attr = "definition")]
    pub definition: Option<Cow<'a, str>>,

    #[xml(attr = "xmi:id")]
    pub id: Cow<'a, str>,

    #[xml(attr = "name")]
    pub name: Cow<'a, str>,

    #[xml(attr = "nextVersions")]
    pub next_versions: Option<Cow<'a, str>>,

    #[xml(attr = "previousVersion")]
    pub previous_version: Option<Cow<'a, str>>,

    #[xml(attr = "registrationStatus")]
    pub registration_status: RegistrationStatus,

    #[xml(attr = "removalDate")]
    pub removal_date: Option<Cow<'a, str>>,

    #[xml(child = "semanticMarkup")]
    pub semantic_markup: Vec<SemanticMarkup<'a>>,
}

#[derive(Debug, XmlRead)]
#[xml(strict(unknown_attribute, unknown_element), tag = "constraint")]
pub struct Constraint<'a> {
    #[xml(attr = "definition")]
    pub definition: Option<Cow<'a, str>>,

    #[xml(attr = "expression")]
    pub expression: Option<Cow<'a, str>>,

    #[xml(attr = "expressionLanguage")]
    pub expression_language: Option<Cow<'a, str>>,

    #[xml(attr = "xmi:id")]
    pub id: Cow<'a, str>,

    #[xml(attr = "name")]
    pub name: Cow<'a, str>,

    #[xml(attr = "nextVersions")]
    pub next_versions: Option<Cow<'a, str>>,

    #[xml(attr = "previousVersion")]
    pub previous_version: Option<Cow<'a, str>>,

    #[xml(attr = "registrationStatus")]
    pub registration_status: RegistrationStatus,
}

#[derive(Debug, XmlRead)]
#[xml(strict(unknown_attribute, unknown_element), tag = "dataDictionary")]
pub struct DataDictionary<'a> {
    #[xml(attr = "xmi:id")]
    pub id: Cow<'a, str>,

    #[xml(child = "topLevelDictionaryEntry")]
    pub entries: Vec<TopLevelDictionaryEntry<'a>>,
}

#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum DictionaryEntryType {
    Amount,
    Binary,
    BusinessComponent,
    ChoiceComponent,
    CodeSet,
    Date,
    DateTime,
    ExternalSchema,
    IdentifierSet,
    Indicator,
    MessageComponent,
    Month,
    Quantity,
    Rate,
    SchemaType,
    Text,
    Time,
    UserDefined,
    Year,
    YearMonth,
}

impl FromStr for DictionaryEntryType {
    type Err = hard_xml::XmlError;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        match value {
            "iso20022:Amount" => Ok(Self::Amount),
            "iso20022:Binary" => Ok(Self::Binary),
            "iso20022:BusinessComponent" => Ok(Self::BusinessComponent),
            "iso20022:ChoiceComponent" => Ok(Self::ChoiceComponent),
            "iso20022:CodeSet" => Ok(Self::CodeSet),
            "iso20022:Date" => Ok(Self::Date),
            "iso20022:DateTime" => Ok(Self::DateTime),
            "iso20022:ExternalSchema" => Ok(Self::ExternalSchema),
            "iso20022:IdentifierSet" => Ok(Self::IdentifierSet),
            "iso20022:Indicator" => Ok(Self::Indicator),
            "iso20022:MessageComponent" => Ok(Self::MessageComponent),
            "iso20022:Month" => Ok(Self::Month),
            "iso20022:Quantity" => Ok(Self::Quantity),
            "iso20022:Rate" => Ok(Self::Rate),
            "iso20022:SchemaType" => Ok(Self::SchemaType),
            "iso20022:Text" => Ok(Self::Text),
            "iso20022:Time" => Ok(Self::Time),
            "iso20022:UserDefined" => Ok(Self::UserDefined),
            "iso20022:Year" => Ok(Self::Year),
            "iso20022:YearMonth" => Ok(Self::YearMonth),
            _ => Err(XmlError::UnrecognizedSymbol {
                symbol: value.into(),
            }),
        }
    }
}

#[derive(Debug, XmlRead)]
#[xml(strict(unknown_attribute, unknown_element), tag = "doclet")]
pub struct Doclet<'a> {
    #[xml(attr = "content")]
    pub content: Option<Cow<'a, str>>,

    #[xml(attr = "xmi:id")]
    pub id: Cow<'a, str>,

    #[xml(attr = "type")]
    pub typ: DocletType,
}

#[derive(Debug)]
pub enum DocletType {
    DocInfoDate,
    DocInfoSubTitle,
    DocInfoTitle,
    Purpose,
}

impl FromStr for DocletType {
    type Err = hard_xml::XmlError;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        match value {
            "docInfoDate" => Ok(Self::DocInfoDate),
            "docInfoSubTitle" => Ok(Self::DocInfoSubTitle),
            "docInfoTitle" => Ok(Self::DocInfoTitle),
            "purpose" => Ok(Self::Purpose),
            _ => Err(XmlError::UnrecognizedSymbol {
                symbol: value.into(),
            }),
        }
    }
}

#[derive(Debug, XmlRead)]
#[xml(strict(unknown_attribute, unknown_element), tag = "element")]
pub struct Element<'a> {
    #[xml(attr = "complexType")]
    pub complex_type: Option<Cow<'a, str>>,

    #[xml(attr = "definition")]
    pub definition: Cow<'a, str>,

    #[xml(attr = "derivation")]
    pub derivation: Option<Cow<'a, str>>,

    #[xml(attr = "xmi:id")]
    pub id: Cow<'a, str>,

    #[xml(attr = "isDerived")]
    pub is_derived: bool,

    #[xml(attr = "maxOccurs")]
    pub max_occurs: Option<usize>,

    #[xml(attr = "minOccurs")]
    pub min_occurs: usize,

    #[xml(attr = "name")]
    pub name: Cow<'a, str>,

    #[xml(attr = "opposite")]
    pub oppositetype: Option<Cow<'a, str>>,

    #[xml(attr = "type")]
    pub r#type: Option<Cow<'a, str>>,

    #[xml(attr = "registrationStatus")]
    pub registration_status: RegistrationStatus,

    #[xml(child = "semanticMarkup")]
    pub semantic_markup: Vec<SemanticMarkup<'a>>,

    #[xml(attr = "simpleType")]
    pub simple_type: Option<Cow<'a, str>>,

    #[xml(attr = "xsi:type")]
    pub typ: ElementType,
}

#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum ElementType {
    BusinessAssociationEnd,
    BusinessAttribute,
}

impl FromStr for ElementType {
    type Err = hard_xml::XmlError;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        match value {
            "iso20022:BusinessAssociationEnd" => Ok(Self::BusinessAssociationEnd),
            "iso20022:BusinessAttribute" => Ok(Self::BusinessAttribute),
            _ => Err(XmlError::UnrecognizedSymbol {
                symbol: value.into(),
            }),
        }
    }
}

#[derive(Debug, XmlRead)]
#[xml(strict(unknown_attribute, unknown_element), tag = "example")]
pub struct Example<'a> {
    #[xml(text)]
    pub value: Cow<'a, str>,
}

#[derive(Debug, XmlRead)]
#[xml(
    strict(unknown_attribute, unknown_element),
    tag = "messageBuildingBlock"
)]
pub struct MessageBuildingBlock<'a> {
    #[xml(attr = "complexType")]
    pub complex_type: Option<Cow<'a, str>>,

    #[xml(attr = "definition")]
    pub definition: Option<Cow<'a, str>>,

    #[xml(child = "example")]
    pub example: Option<Example<'a>>,

    #[xml(attr = "xmi:id")]
    pub id: Cow<'a, str>,

    #[xml(attr = "maxOccurs")]
    pub max_occurs: Option<usize>,

    #[xml(attr = "minOccurs")]
    pub min_occurs: usize,

    #[xml(attr = "name")]
    pub name: Cow<'a, str>,

    #[xml(attr = "nextVersions")]
    pub next_versions: Option<Cow<'a, str>>,

    #[xml(attr = "previousVersion")]
    pub previous_version: Option<Cow<'a, str>>,

    #[xml(attr = "registrationStatus")]
    pub registration_status: RegistrationStatus,

    #[xml(child = "semanticMarkup")]
    pub semantic_markup: Vec<SemanticMarkup<'a>>,

    #[xml(attr = "simpleType")]
    pub simple_type: Option<Cow<'a, str>>,

    #[xml(attr = "xmlTag")]
    pub xml_tag: Cow<'a, str>,
}

#[derive(Debug, XmlRead)]
#[xml(strict(unknown_attribute, unknown_element), tag = "messageDefinition")]
pub struct MessageDefinition<'a> {
    #[xml(child = "messageBuildingBlock")]
    pub building_blocks: Vec<MessageBuildingBlock<'a>>,

    #[xml(child = "constraint")]
    pub constraints: Vec<Constraint<'a>>,

    #[xml(attr = "definition")]
    pub definition: Cow<'a, str>,

    #[xml(child = "doclet")]
    pub doclets: Vec<Doclet<'a>>,

    #[xml(attr = "xmi:id")]
    pub id: Cow<'a, str>,

    #[xml(child = "messageDefinitionIdentifier")]
    pub identifier: MessageDefinitionIdentifier<'a>,

    #[xml(attr = "messageSet")]
    pub message_set: Option<Cow<'a, str>>,

    #[xml(attr = "name")]
    pub name: Cow<'a, str>,

    #[xml(attr = "nextVersions")]
    pub next_versions: Option<Cow<'a, str>>,

    #[xml(attr = "previousVersion")]
    pub previous_version: Option<Cow<'a, str>>,

    #[xml(attr = "registrationStatus")]
    pub registration_status: RegistrationStatus,

    #[xml(attr = "rootElement")]
    pub root_element: Cow<'a, str>,

    #[xml(child = "semanticMarkup")]
    pub semantic_markup: Vec<SemanticMarkup<'a>>,

    #[xml(attr = "xmlName")]
    pub xml_name: Option<Cow<'a, str>>,

    #[xml(attr = "xmlTag")]
    pub xml_tag: Cow<'a, str>,

    #[xml(child = "xors")]
    pub xors: Vec<Xor<'a>>,
}

#[derive(Clone, Debug, XmlRead)]
#[xml(
    strict(unknown_attribute, unknown_element),
    tag = "messageDefinitionIdentifier"
)]
pub struct MessageDefinitionIdentifier<'a> {
    #[xml(attr = "businessArea")]
    pub business_area: Cow<'a, str>,

    #[xml(attr = "flavour")]
    pub flavour: Cow<'a, str>,

    #[xml(attr = "messageFunctionality")]
    pub functionality: Cow<'a, str>,

    #[xml(attr = "version")]
    pub version: Cow<'a, str>,
}

impl MessageDefinitionIdentifier<'_> {
    pub fn xml_namespace(&self) -> String {
        let Self {
            business_area,
            flavour,
            functionality,
            version,
        } = self;
        format!(
            "urn:iso:std:iso:20022:tech:xsd:{business_area}.{functionality}.{flavour}.{version}"
        )
    }
}

#[derive(Debug, XmlRead)]
#[xml(strict(unknown_attribute, unknown_element), tag = "messageElement")]
pub struct MessageElement<'a> {
    #[xml(attr = "businessComponentTrace")]
    pub business_component_trace: Option<Cow<'a, str>>,

    #[xml(attr = "businessElementTrace")]
    pub business_element_trace: Option<Cow<'a, str>>,

    #[xml(attr = "complexType")]
    pub complex_type: Option<Cow<'a, str>>,

    #[xml(child = "constraint")]
    pub constraints: Vec<Constraint<'a>>,

    #[xml(attr = "definition")]
    pub definition: Option<Cow<'a, str>>,

    #[xml(attr = "xsi:type")]
    pub element_type: MessageElementType,

    #[xml(child = "example")]
    pub example: Option<Example<'a>>,

    #[xml(attr = "xmi:id")]
    pub id: Cow<'a, str>,

    #[xml(attr = "isComposite")]
    pub is_composite: Option<bool>,

    #[xml(attr = "isDerived")]
    pub is_derived: bool,

    #[xml(attr = "maxOccurs")]
    pub max_occurs: Option<usize>,

    #[xml(attr = "minOccurs")]
    pub min_occurs: usize,

    #[xml(attr = "name")]
    pub name: Cow<'a, str>,

    #[xml(attr = "nextVersions")]
    pub next_versions: Option<Cow<'a, str>>,

    #[xml(attr = "previousVersion")]
    pub previous_version: Option<Cow<'a, str>>,

    #[xml(attr = "registrationStatus")]
    pub registration_status: RegistrationStatus,

    #[xml(attr = "removalDate")]
    pub removal_date: Option<Cow<'a, str>>,

    #[xml(child = "semanticMarkup")]
    pub semantic_markup: Vec<SemanticMarkup<'a>>,

    #[xml(attr = "simpleType")]
    pub simple_type: Option<Cow<'a, str>>,

    #[xml(attr = "type")]
    pub typ: Option<Cow<'a, str>>,

    #[xml(attr = "xmlTag")]
    pub xml_tag: Cow<'a, str>,
}

impl<'a> MessageElement<'a> {
    pub fn data_type(&self) -> Option<&Cow<'a, str>> {
        let Self {
            complex_type,
            simple_type,
            typ,
            ..
        } = self;
        if let (None, None, Some(typ)) | (None, Some(typ), None) | (Some(typ), None, None) =
            (complex_type, simple_type, typ)
        {
            Some(typ)
        } else {
            None
        }
    }
}

#[derive(Debug)]
pub enum MessageElementType {
    AssociationEnd,
    Attribute,
}

impl FromStr for MessageElementType {
    type Err = hard_xml::XmlError;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        match value {
            "iso20022:MessageAssociationEnd" => Ok(Self::AssociationEnd),
            "iso20022:MessageAttribute" => Ok(Self::Attribute),
            _ => Err(XmlError::UnrecognizedSymbol {
                symbol: value.into(),
            }),
        }
    }
}

#[derive(Debug, XmlRead)]
#[xml(strict(unknown_attribute, unknown_element), tag = "namespaceList")]
pub struct NamespaceList<'a> {
    #[xml(text)]
    pub namespace: Cow<'a, str>,
}

#[derive(Debug)]
pub enum RegistrationStatus {
    Obsolete,
    ProvisionallyRegistered,
    Registered,
}

impl FromStr for RegistrationStatus {
    type Err = hard_xml::XmlError;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        match value {
            "Obsolete" => Ok(Self::Obsolete),
            "Provisionally Registered" => Ok(Self::ProvisionallyRegistered),
            "Registered" => Ok(Self::Registered),
            _ => Err(XmlError::UnrecognizedSymbol {
                symbol: value.into(),
            }),
        }
    }
}

#[derive(Debug, XmlRead)]
#[xml(
    strict(unknown_attribute, unknown_element),
    tag = "iso20022:Repository"
)]
pub struct Repository<'a> {
    #[xml(child = "businessProcessCatalogue")]
    pub business_process_catalogue: BusinessProcessCatalogue<'a>,

    #[xml(child = "dataDictionary")]
    pub data_dictionary: DataDictionary<'a>,

    #[xml(attr = "xmi:id")]
    pub id: Cow<'a, str>,

    #[xml(attr = "xmlns:iso20022")]
    pub iso20022: Cow<'a, str>,

    #[xml(attr = "xmi:version")]
    pub version: Cow<'a, str>,

    #[xml(attr = "xmlns:xmi")]
    pub xmi: Cow<'a, str>,

    #[xml(attr = "xmlns:xsi")]
    pub xsi: Cow<'a, str>,
}

#[derive(Debug, XmlRead)]
#[xml(strict(unknown_attribute, unknown_element), tag = "semanticMarkup")]
pub struct SemanticMarkup<'a> {
    #[xml(attr = "xmi:id")]
    pub id: Cow<'a, str>,

    #[xml(attr = "type")]
    pub typ: SemanticMarkupType,

    #[xml(child = "elements")]
    pub elements: Vec<SemanticMarkupElement<'a>>,
}

#[derive(Debug, XmlRead)]
#[xml(strict(unknown_attribute, unknown_element), tag = "elements")]
pub struct SemanticMarkupElement<'a> {
    #[xml(attr = "xmi:id")]
    pub id: Cow<'a, str>,

    #[xml(attr = "name")]
    pub name: Cow<'a, str>,

    #[xml(attr = "value")]
    pub value: Cow<'a, str>,
}

#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum SemanticMarkupType {
    AdminComment,
    BusinessComment,
    ExternalCodeAttribute,
    ExternalCodeSetAttribute,
    Favorite,
    SampleData,
    Synonym,
    Prefix,
}

impl FromStr for SemanticMarkupType {
    type Err = hard_xml::XmlError;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        match value {
            "ADMINCOMMENT" | "AdminComment" => Ok(Self::AdminComment),
            "BUSINESSCOMMENT" | "BusinessComment" => Ok(Self::BusinessComment),
            "ExternalCodeAttribute" => Ok(Self::ExternalCodeAttribute),
            "ExternalCodeSetAttribute" => Ok(Self::ExternalCodeSetAttribute),
            "Favorite" => Ok(Self::Favorite),
            "SampleData" => Ok(Self::SampleData),
            "Synonym" => Ok(Self::Synonym),
            "prefix" => Ok(Self::Prefix),
            _ => Err(XmlError::UnrecognizedSymbol {
                symbol: value.into(),
            }),
        }
    }
}

#[derive(Debug, XmlRead)]
#[xml(
    strict(unknown_attribute, unknown_element),
    tag = "topLevelCatalogueEntry"
)]
pub struct TopLevelCatalogueEntry<'a> {
    #[xml(child = "businessRole")]
    pub business_roles: Vec<BusinessRole<'a>>,

    #[xml(attr = "code")]
    pub code: Option<Cow<'a, str>>,

    #[xml(attr = "definition")]
    pub definition: Option<Cow<'a, str>>,

    #[xml(child = "doclet")]
    pub doclets: Vec<Doclet<'a>>,

    #[xml(attr = "xmi:id")]
    pub id: Cow<'a, str>,

    #[xml(attr = "messageDefinition")]
    pub message_definition: Option<Cow<'a, str>>,

    #[xml(child = "messageDefinition")]
    pub message_definitions: Vec<MessageDefinition<'a>>,

    #[xml(attr = "name")]
    pub name: Cow<'a, str>,

    #[xml(attr = "registrationStatus")]
    pub registration_status: RegistrationStatus,

    #[xml(attr = "xsi:type")]
    pub typ: CatalogueEntryType,
}

#[derive(Debug, XmlRead)]
#[xml(
    strict(unknown_attribute, unknown_element),
    tag = "topLevelDictionaryEntry"
)]
pub struct TopLevelDictionaryEntry<'a> {
    #[xml(attr = "associationDomain")]
    pub association_domain: Option<Cow<'a, str>>,

    #[xml(attr = "baseValue")]
    pub base_value: Option<Decimal>,

    #[xml(attr = "messageBuildingBlock")]
    pub building_block: Option<Cow<'a, str>>,

    #[xml(child = "code")]
    pub codes: Vec<Code<'a>>,

    #[xml(child = "constraint")]
    pub constraints: Vec<Constraint<'a>>,

    #[xml(attr = "currencyIdentifierSet")]
    pub currency_identifier_set: Option<Cow<'a, str>>,

    #[xml(attr = "definition")]
    pub definition: Option<Cow<'a, str>>,

    #[xml(attr = "derivation")]
    pub derivation: Option<Cow<'a, str>>,

    #[xml(attr = "derivationComponent")]
    pub derivation_component: Option<Cow<'a, str>>,

    #[xml(attr = "derivationElement")]
    pub derivation_element: Option<Cow<'a, str>>,

    #[xml(child = "element")]
    pub elements: Vec<Element<'a>>,

    #[xml(child = "example")]
    pub example: Option<Example<'a>>,

    #[xml(attr = "fractionDigits")]
    pub fraction_digits: Option<u32>,

    #[xml(attr = "xmi:id")]
    pub id: Cow<'a, str>,

    #[xml(attr = "identificationScheme")]
    pub identification_scheme: Option<Cow<'a, str>>,

    #[xml(attr = "kind")]
    pub kind: Option<Cow<'a, str>>,

    #[xml(attr = "length")]
    pub length: Option<usize>,

    #[xml(attr = "maxInclusive")]
    pub max_inclusive: Option<Cow<'a, str>>,

    #[xml(attr = "maxLength")]
    pub max_length: Option<usize>,

    #[xml(attr = "meaningWhenFalse")]
    pub meaning_when_false: Option<Cow<'a, str>>,

    #[xml(attr = "meaningWhenTrue")]
    pub meaning_when_true: Option<Cow<'a, str>>,

    #[xml(child = "messageElement")]
    pub message_elements: Vec<MessageElement<'a>>,

    #[xml(attr = "minInclusive")]
    pub min_inclusive: Option<Cow<'a, str>>,

    #[xml(attr = "minLength")]
    pub min_length: Option<usize>,

    #[xml(attr = "name")]
    pub name: Cow<'a, str>,

    #[xml(attr = "namespace")]
    pub namespace: Option<Cow<'a, str>>,

    #[xml(attr = "namespaceList")]
    pub namespace_list_attr: Option<Cow<'a, str>>,

    #[xml(child = "namespaceList")]
    pub namespace_list_child: Vec<NamespaceList<'a>>,

    #[xml(attr = "nextVersions")]
    pub next_versions: Option<Cow<'a, str>>,

    #[xml(attr = "pattern")]
    pub pattern: Option<Cow<'a, str>>,

    #[xml(attr = "previousVersion")]
    pub previous_version: Option<Cow<'a, str>>,

    #[xml(attr = "processContent")]
    pub process_content: Option<Cow<'a, str>>,

    #[xml(attr = "processContents")]
    pub process_contents: Option<Cow<'a, str>>,

    #[xml(attr = "registrationStatus")]
    pub registration_status: RegistrationStatus,

    #[xml(attr = "removalDate")]
    pub removal_date: Option<Cow<'a, str>>,

    #[xml(child = "semanticMarkup")]
    pub semantic_markup: Vec<SemanticMarkup<'a>>,

    #[xml(attr = "subType")]
    pub sub_type: Option<Cow<'a, str>>,

    #[xml(attr = "superType")]
    pub super_type: Option<Cow<'a, str>>,

    #[xml(attr = "totalDigits")]
    pub total_digits: Option<u32>,

    #[xml(attr = "trace")]
    pub trace: Option<Cow<'a, str>>,

    #[xml(attr = "xsi:type")]
    pub typ: DictionaryEntryType,

    #[xml(child = "xors")]
    pub xors: Vec<Xor<'a>>,
}

impl TopLevelDictionaryEntry<'_> {
    pub fn ident(&self) -> Ident {
        parse_identifier(&self.name.to_pascal_case()).unwrap()
    }

    pub fn type_name(&self) -> Type {
        TypePath {
            qself: None,
            path: self.ident().into(),
        }
        .into()
    }
}

#[derive(Debug, XmlRead)]
#[xml(strict(unknown_attribute, unknown_element), tag = "xors")]
pub struct Xor<'a> {
    #[xml(attr = "definition")]
    pub definition: Option<Cow<'a, str>>,

    #[xml(attr = "xmi:id")]
    pub id: Cow<'a, str>,

    #[xml(attr = "name")]
    pub name: Cow<'a, str>,

    #[xml(attr = "registrationStatus")]
    pub registration_status: RegistrationStatus,

    #[xml(attr = "impactedElements")]
    pub impacted_elements: Option<Cow<'a, str>>,

    #[xml(attr = "impactedMessageBuildingBlocks")]
    pub impacted_message_building_blocks: Option<Cow<'a, str>>,
}

pub fn parse_identifier(ident: &str) -> Result<Ident, syn::Error> {
    let result = parse_str(ident);
    if result.is_ok() {
        result
    } else if let Ok(ident) = parse_str(&format!("r#{ident}")) {
        Ok(ident)
    } else {
        result
    }
}