1
use crate::common::PropertyKind;
2
use crate::model::object::ICalObject;
3
use crate::model::property::CalendarProperty;
4
use crate::validate::error::CalendarPropertyError;
5
use crate::validate::params::validate_params;
6
use crate::validate::{
7
    calendar_property_name, check_occurrence, CalendarInfo, CalendarPropertyLocation,
8
    ICalendarErrorSeverity, OccurrenceExpectation, PropertyInfo, PropertyLocation, ValueType,
9
};
10
use std::collections::HashMap;
11

            
12
188
pub(super) fn validate_calendar_properties(
13
188
    ical_object: &ICalObject,
14
188
    calendar_info: &mut CalendarInfo,
15
188
) -> Vec<CalendarPropertyError> {
16
188
    let mut errors = Vec::new();
17
188

            
18
188
    let mut seen = HashMap::<String, u32>::new();
19
564
    let add_count = |seen: &mut HashMap<String, u32>, key: &str| {
20
474
        *seen
21
474
            .entry(key.to_string())
22
474
            .and_modify(|count| *count += 1)
23
474
            .or_insert(1)
24
474
    };
25
474
    for (index, property) in ical_object.properties.iter().enumerate() {
26
474
        match property {
27
            CalendarProperty::ProductId(_) => {
28
188
                let name = calendar_property_name(property);
29
188
                add_count(&mut seen, name);
30

            
31
188
                if let Some(message) = check_occurrence(&seen, name, OccurrenceExpectation::Once) {
32
                    errors.push(CalendarPropertyError {
33
                        message,
34
                        severity: ICalendarErrorSeverity::Error,
35
                        location: Some(CalendarPropertyLocation {
36
                            index,
37
                            name: name.to_string(),
38
                            property_location: None,
39
                        }),
40
                    })
41
188
                }
42
            }
43
188
            CalendarProperty::Version(version) => {
44
188
                let name = calendar_property_name(property);
45
188
                add_count(&mut seen, name);
46

            
47
188
                if let Some(message) = check_occurrence(&seen, name, OccurrenceExpectation::Once) {
48
                    errors.push(CalendarPropertyError {
49
                        message,
50
                        severity: ICalendarErrorSeverity::Error,
51
                        location: Some(CalendarPropertyLocation {
52
                            index,
53
                            name: name.to_string(),
54
                            property_location: None,
55
                        }),
56
                    })
57
188
                }
58

            
59
188
                let property_info = PropertyInfo::new(
60
188
                    calendar_info,
61
188
                    PropertyLocation::Calendar,
62
188
                    PropertyKind::Version,
63
188
                    ValueType::VersionValue,
64
188
                );
65
188
                errors.extend_from_slice(
66
188
                    CalendarPropertyError::many_from_param_errors(
67
188
                        validate_params(&version.params, property_info),
68
188
                        index,
69
188
                        calendar_property_name(property).to_string(),
70
188
                    )
71
188
                    .as_slice(),
72
188
                );
73
            }
74
            CalendarProperty::CalendarScale(_) => {
75
6
                let name = calendar_property_name(property);
76
6
                add_count(&mut seen, name);
77

            
78
                if let Some(message) =
79
6
                    check_occurrence(&seen, name, OccurrenceExpectation::OptionalOnce)
80
                {
81
                    errors.push(CalendarPropertyError {
82
                        message,
83
                        severity: ICalendarErrorSeverity::Error,
84
                        location: Some(CalendarPropertyLocation {
85
                            index,
86
                            name: name.to_string(),
87
                            property_location: None,
88
                        }),
89
                    })
90
6
                }
91
            }
92
92
            CalendarProperty::Method(method) => {
93
92
                if calendar_info.method.is_none() {
94
92
                    calendar_info.method = Some(method.value.clone());
95
92
                }
96

            
97
92
                let name = calendar_property_name(property);
98
92
                add_count(&mut seen, name);
99

            
100
                if let Some(message) =
101
92
                    check_occurrence(&seen, name, OccurrenceExpectation::OptionalOnce)
102
                {
103
                    errors.push(CalendarPropertyError {
104
                        message,
105
                        severity: ICalendarErrorSeverity::Error,
106
                        location: Some(CalendarPropertyLocation {
107
                            index,
108
                            name: name.to_string(),
109
                            property_location: None,
110
                        }),
111
                    })
112
92
                }
113
            }
114
            _ => {
115
                // Nothing further to validate
116
            }
117
        }
118
    }
119

            
120
    // Check required properties, in case they were missing. If they are specified more than once
121
    // then it will produce duplicate errors.
122
188
    if let Some(message) = check_occurrence(&seen, "PRODID", OccurrenceExpectation::Once) {
123
        errors.push(CalendarPropertyError {
124
            message,
125
            severity: ICalendarErrorSeverity::Error,
126
            location: None,
127
        })
128
188
    }
129
188
    if let Some(message) = check_occurrence(&seen, "VERSION", OccurrenceExpectation::Once) {
130
        errors.push(CalendarPropertyError {
131
            message,
132
            severity: ICalendarErrorSeverity::Error,
133
            location: None,
134
        })
135
188
    }
136

            
137
188
    errors
138
188
}