autosar_data_abstraction/ecu_configuration/values/
mod.rsuse crate::{
    abstraction_element,
    ecu_configuration::{
        AbstractEcucContainerDef, AbstractEcucReferenceDef, EcucContainerDef, EcucInstanceReferenceDef, EcucModuleDef,
        EcucNumericalParamDef, EcucTextualParamDef,
    },
    AbstractionElement, ArPackage, AutosarAbstractionError, System,
};
use autosar_data::{Element, ElementName};
mod parameter;
mod reference;
pub use parameter::*;
pub use reference::*;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EcucValueCollection(Element);
abstraction_element!(EcucValueCollection, EcucValueCollection);
impl EcucValueCollection {
    pub(crate) fn new(name: &str, package: &ArPackage) -> Result<Self, AutosarAbstractionError> {
        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
        let ecuc_value_collection_elem = elements.create_named_sub_element(ElementName::EcucValueCollection, name)?;
        Ok(Self(ecuc_value_collection_elem))
    }
    pub fn add_module_configuration(
        &self,
        module_configuration: &EcucModuleConfigurationValues,
    ) -> Result<(), AutosarAbstractionError> {
        let ecuc_values_elem = self.element().get_or_create_sub_element(ElementName::EcucValues)?;
        ecuc_values_elem
            .create_sub_element(ElementName::EcucModuleConfigurationValuesRefConditional)?
            .create_sub_element(ElementName::EcucModuleConfigurationValuesRef)?
            .set_reference_target(module_configuration.element())?;
        Ok(())
    }
    pub fn module_configurations(&self) -> impl Iterator<Item = EcucModuleConfigurationValues> {
        self.element()
            .get_sub_element(ElementName::EcucValues)
            .into_iter()
            .flat_map(|values_elem| values_elem.sub_elements())
            .filter_map(|ref_cond| {
                ref_cond
                    .get_sub_element(ElementName::EcucModuleConfigurationValuesRef)
                    .and_then(|module_config_ref| module_config_ref.get_reference_target().ok())
                    .and_then(|module_elem| EcucModuleConfigurationValues::try_from(module_elem).ok())
            })
    }
    pub fn set_ecu_extract_reference(&self, system: &System) -> Result<(), AutosarAbstractionError> {
        self.element()
            .create_sub_element(ElementName::EcuExtractRef)?
            .set_reference_target(system.element())?;
        Ok(())
    }
    pub fn ecu_extract_reference(&self) -> Option<System> {
        let system_elem = self
            .element()
            .get_sub_element(ElementName::EcuExtractRef)?
            .get_reference_target()
            .ok()?;
        System::try_from(system_elem).ok()
    }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EcucModuleConfigurationValues(Element);
abstraction_element!(EcucModuleConfigurationValues, EcucModuleConfigurationValues);
impl EcucModuleConfigurationValues {
    pub(crate) fn new(
        name: &str,
        package: &ArPackage,
        module_definition: &EcucModuleDef,
    ) -> Result<Self, AutosarAbstractionError> {
        let elements = package.element().get_or_create_sub_element(ElementName::Elements)?;
        let module_config_elem = elements.create_named_sub_element(ElementName::EcucModuleConfigurationValues, name)?;
        let module_config = Self(module_config_elem);
        module_config.set_definition(module_definition)?;
        Ok(module_config)
    }
    pub fn set_definition(&self, module_definition: &EcucModuleDef) -> Result<(), AutosarAbstractionError> {
        self.element()
            .get_or_create_sub_element(ElementName::DefinitionRef)?
            .set_reference_target(module_definition.element())?;
        Ok(())
    }
    pub fn definition(&self) -> Option<EcucModuleDef> {
        let definition_elem = self
            .element()
            .get_sub_element(ElementName::DefinitionRef)?
            .get_reference_target()
            .ok()?;
        EcucModuleDef::try_from(definition_elem).ok()
    }
    pub fn definition_ref(&self) -> Option<String> {
        self.element()
            .get_sub_element(ElementName::DefinitionRef)?
            .character_data()?
            .string_value()
    }
    pub fn create_container_value<T: AbstractEcucContainerDef>(
        &self,
        name: &str,
        definition: &T,
    ) -> Result<EcucContainerValue, AutosarAbstractionError> {
        let containers_elem = self.element().get_or_create_sub_element(ElementName::Containers)?;
        EcucContainerValue::new(name, &containers_elem, definition)
    }
    pub fn container_values(&self) -> impl Iterator<Item = EcucContainerValue> {
        self.element()
            .get_sub_element(ElementName::Containers)
            .into_iter()
            .flat_map(|containers_elem| containers_elem.sub_elements())
            .filter_map(|container_elem| EcucContainerValue::try_from(container_elem).ok())
    }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EcucContainerValue(Element);
abstraction_element!(EcucContainerValue, EcucContainerValue);
impl EcucContainerValue {
    pub(crate) fn new<T: AbstractEcucContainerDef>(
        name: &str,
        parent: &Element,
        definition: &T,
    ) -> Result<Self, AutosarAbstractionError> {
        let container_value_elem = parent.create_named_sub_element(ElementName::EcucContainerValue, name)?;
        let container_value = Self(container_value_elem);
        container_value.set_definition(definition)?;
        Ok(container_value)
    }
    pub fn set_definition<T: AbstractEcucContainerDef>(&self, definition: &T) -> Result<(), AutosarAbstractionError> {
        self.element()
            .get_or_create_sub_element(ElementName::DefinitionRef)?
            .set_reference_target(definition.element())?;
        Ok(())
    }
    pub fn definition(&self) -> Option<EcucContainerDef> {
        let definition_elem = self
            .element()
            .get_sub_element(ElementName::DefinitionRef)?
            .get_reference_target()
            .ok()?;
        EcucContainerDef::try_from(definition_elem).ok()
    }
    pub fn definition_ref(&self) -> Option<String> {
        self.element()
            .get_sub_element(ElementName::DefinitionRef)?
            .character_data()?
            .string_value()
    }
    pub fn create_sub_container<T: AbstractEcucContainerDef>(
        &self,
        name: &str,
        definition: &T,
    ) -> Result<EcucContainerValue, AutosarAbstractionError> {
        let sub_containers_elem = self.element().get_or_create_sub_element(ElementName::SubContainers)?;
        EcucContainerValue::new(name, &sub_containers_elem, definition)
    }
    pub fn sub_containers(&self) -> impl Iterator<Item = EcucContainerValue> {
        self.element()
            .get_sub_element(ElementName::SubContainers)
            .into_iter()
            .flat_map(|sub_containers| sub_containers.sub_elements())
            .filter_map(|elem| EcucContainerValue::try_from(elem).ok())
    }
    pub fn set_index(&self, index: Option<u64>) -> Result<(), AutosarAbstractionError> {
        if let Some(index) = index {
            self.element()
                .get_or_create_sub_element(ElementName::Index)?
                .set_character_data(index)?;
        } else {
            self.element().remove_sub_element_kind(ElementName::Index)?;
        }
        Ok(())
    }
    pub fn index(&self) -> Option<u64> {
        self.element()
            .get_sub_element(ElementName::Index)?
            .character_data()?
            .parse_integer()
    }
    pub fn create_numerical_param_value<T: EcucNumericalParamDef>(
        &self,
        definition: &T,
        value: &str,
    ) -> Result<EcucNumericalParamValue, AutosarAbstractionError> {
        let parameter_values_elem = self.element().get_or_create_sub_element(ElementName::ParameterValues)?;
        EcucNumericalParamValue::new(¶meter_values_elem, definition, value)
    }
    pub fn create_textual_param_value<T: EcucTextualParamDef>(
        &self,
        definition: &T,
        value: &str,
    ) -> Result<EcucTextualParamValue, AutosarAbstractionError> {
        let parameter_values_elem = self.element().get_or_create_sub_element(ElementName::ParameterValues)?;
        EcucTextualParamValue::new(¶meter_values_elem, definition, value)
    }
    pub fn parameter_values(&self) -> impl Iterator<Item = EcucParameterValue> {
        self.element()
            .get_sub_element(ElementName::ParameterValues)
            .into_iter()
            .flat_map(|param_values_elem| param_values_elem.sub_elements())
            .filter_map(|param_elem| EcucParameterValue::try_from(param_elem).ok())
    }
    pub fn create_instance_reference(
        &self,
        definition: &EcucInstanceReferenceDef,
        target_context: &[&Element],
        target: &Element,
    ) -> Result<EcucInstanceReferenceValue, AutosarAbstractionError> {
        let reference_values_elem = self.element().get_or_create_sub_element(ElementName::ReferenceValues)?;
        EcucInstanceReferenceValue::new(&reference_values_elem, definition, target_context, target)
    }
    pub fn create_reference_value<T: AbstractEcucReferenceDef>(
        &self,
        definition: &T,
        target: &Element,
    ) -> Result<EcucReferenceValue, AutosarAbstractionError> {
        let reference_values_elem = self.element().get_or_create_sub_element(ElementName::ReferenceValues)?;
        EcucReferenceValue::new(&reference_values_elem, definition, target)
    }
    pub fn reference_values(&self) -> impl Iterator<Item = EcucAnyReferenceValue> {
        self.element()
            .get_sub_element(ElementName::ReferenceValues)
            .into_iter()
            .flat_map(|reference_values_elem| reference_values_elem.sub_elements())
            .filter_map(|reference_elem| EcucAnyReferenceValue::try_from(reference_elem).ok())
    }
}
#[cfg(test)]
mod test {
    use crate::{system, AbstractionElement, ArPackage};
    use autosar_data::{AutosarModel, AutosarVersion, ElementName};
    #[test]
    fn test_ecu_configuration_values() {
        let definition_model = AutosarModel::new();
        let _file = definition_model
            .create_file("definition.arxml", AutosarVersion::LATEST)
            .unwrap();
        let def_package = ArPackage::get_or_create(&definition_model, "/def_package").unwrap();
        let values_model = AutosarModel::new();
        let _file = values_model
            .create_file("values.arxml", AutosarVersion::LATEST)
            .unwrap();
        let val_package = ArPackage::get_or_create(&values_model, "/val_package").unwrap();
        let module_def = def_package.create_ecuc_module_def("ModuleDef").unwrap();
        let container_def = module_def.create_param_conf_container_def("ContainerDef").unwrap();
        let ecuc_value_collection = val_package.create_ecuc_value_collection("EcucValues").unwrap();
        assert_eq!(ecuc_value_collection.ecu_extract_reference(), None);
        let system = val_package
            .create_system("System", system::SystemCategory::EcuExtract)
            .unwrap();
        ecuc_value_collection.set_ecu_extract_reference(&system).unwrap();
        assert_eq!(ecuc_value_collection.ecu_extract_reference().unwrap(), system);
        assert_eq!(ecuc_value_collection.module_configurations().count(), 0);
        let ecuc_config_values = val_package
            .create_ecuc_module_configuration_values("Module", &module_def)
            .unwrap();
        ecuc_value_collection
            .add_module_configuration(&ecuc_config_values)
            .unwrap();
        assert_eq!(ecuc_value_collection.module_configurations().count(), 1);
        assert_eq!(ecuc_config_values.definition_ref(), module_def.element().path().ok());
        assert!(ecuc_config_values.definition().is_none());
        let container_values = ecuc_config_values
            .create_container_value("Container", &container_def)
            .unwrap();
        assert_eq!(container_values.definition_ref(), container_def.element().path().ok());
        assert!(container_values.definition().is_none());
        assert_eq!(container_values.index(), None);
        container_values.set_index(Some(0)).unwrap();
        assert_eq!(container_values.index(), Some(0));
        assert_eq!(ecuc_config_values.container_values().count(), 1);
        let sub_container_value = container_values
            .create_sub_container("SubContainer", &container_def)
            .unwrap();
        assert_eq!(
            sub_container_value.definition_ref(),
            container_def.element().path().ok()
        );
        assert_eq!(container_values.sub_containers().count(), 1);
        values_model
            .root_element()
            .get_sub_element(ElementName::ArPackages)
            .unwrap()
            .create_copied_sub_element(def_package.element())
            .unwrap();
        }
}