1
use std::fmt::{Display, Formatter};
2

            
3
#[derive(Clone, PartialEq, Debug)]
4
pub enum ICalendarErrorSeverity {
5
    /// Invalid according to the iCalendar specification.
6
    Error,
7
    /// Non-fatal issue that could be fixed but can be ignored.
8
    ///
9
    /// For example, redundant VALUE parameters or unnecessary WKST properties in an RRULE.
10
    Warning,
11
}
12

            
13
#[derive(Clone)]
14
pub struct ICalendarError {
15
    pub message: String,
16
    pub severity: ICalendarErrorSeverity,
17
    pub location: Option<ICalendarLocation>,
18
}
19

            
20
impl Display for ICalendarError {
21
488
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
22
488
        if let Some(location) = &self.location {
23
486
            match location {
24
36
                ICalendarLocation::CalendarProperty(cp) => {
25
36
                    write!(
26
36
                        f,
27
36
                        "In calendar property \"{}\" at index {}",
28
36
                        cp.name, cp.index
29
36
                    )?;
30
                }
31
450
                ICalendarLocation::Component(component) => {
32
450
                    write!(
33
450
                        f,
34
450
                        "In component \"{}\" at index {}",
35
450
                        component.name, component.index
36
450
                    )?;
37
450
                    if let Some(within) = &component.location {
38
418
                        match &**within {
39
358
                            WithinComponentLocation::Property(cp) => {
40
358
                                write!(
41
358
                                    f,
42
358
                                    ", in component property \"{}\" at index {}",
43
358
                                    cp.name, cp.index
44
358
                                )?;
45
                            }
46
60
                            WithinComponentLocation::Component(nested_component_location) => {
47
60
                                write!(
48
60
                                    f,
49
60
                                    ", in nested component \"{}\" at index {}",
50
60
                                    nested_component_location.name, nested_component_location.index
51
60
                                )?;
52

            
53
60
                                if let Some(nested_within) = &nested_component_location.location {
54
20
                                    if let WithinComponentLocation::Property(cp) = &**nested_within
55
                                    {
56
20
                                        write!(
57
20
                                            f,
58
20
                                            ", in nested component property \"{}\" at index {}",
59
20
                                            cp.name, cp.index
60
20
                                        )?;
61
                                    }
62
40
                                }
63
                            }
64
                        }
65
32
                    }
66
                }
67
            }
68

            
69
486
            write!(f, ": {}", self.message)
70
        } else {
71
2
            write!(f, "{}", self.message)
72
        }
73
488
    }
74
}
75

            
76
impl ICalendarError {
77
188
    pub(super) fn many_from_calendar_property_errors(
78
188
        errors: Vec<CalendarPropertyError>,
79
188
    ) -> Vec<Self> {
80
188
        errors
81
188
            .into_iter()
82
206
            .map(|error| ICalendarError {
83
36
                message: error.message,
84
36
                severity: error.severity,
85
36
                location: error.location.map(ICalendarLocation::CalendarProperty),
86
206
            })
87
188
            .collect()
88
188
    }
89

            
90
248
    pub(super) fn many_from_component_property_errors(
91
248
        errors: Vec<ComponentPropertyError>,
92
248
        index: usize,
93
248
        name: String,
94
248
    ) -> Vec<Self> {
95
248
        errors
96
248
            .into_iter()
97
539
            .map(|error| ICalendarError {
98
388
                message: error.message,
99
388
                severity: error.severity,
100
388
                location: Some(ICalendarLocation::Component(ComponentLocation {
101
388
                    index,
102
388
                    name: name.clone(),
103
388
                    location: error
104
388
                        .location
105
388
                        .map(|l| Box::new(WithinComponentLocation::Property(l))),
106
388
                })),
107
539
            })
108
248
            .collect()
109
248
    }
110

            
111
100
    pub(super) fn many_from_nested_component_property_errors(
112
100
        errors: Vec<ComponentPropertyError>,
113
100
        index: usize,
114
100
        name: String,
115
100
        nested_index: usize,
116
100
        nested_name: String,
117
100
    ) -> Vec<Self> {
118
100
        errors
119
100
            .into_iter()
120
134
            .map(|error| ICalendarError {
121
60
                message: error.message,
122
60
                severity: error.severity,
123
60
                location: Some(ICalendarLocation::Component(ComponentLocation {
124
60
                    index,
125
60
                    name: name.clone(),
126
60
                    location: Some(
127
60
                        WithinComponentLocation::Component(ComponentLocation {
128
60
                            index: nested_index,
129
60
                            name: nested_name.clone(),
130
60
                            location: error
131
60
                                .location
132
60
                                .map(|l| Box::new(WithinComponentLocation::Property(l))),
133
60
                        })
134
60
                        .into(),
135
60
                    ),
136
60
                })),
137
134
            })
138
100
            .collect()
139
100
    }
140
}
141

            
142
#[derive(Clone)]
143
pub enum ICalendarLocation {
144
    CalendarProperty(CalendarPropertyLocation),
145
    Component(ComponentLocation),
146
}
147

            
148
#[derive(Clone)]
149
pub struct ComponentLocation {
150
    pub index: usize,
151
    pub name: String,
152
    pub location: Option<Box<WithinComponentLocation>>,
153
}
154

            
155
#[derive(Clone)]
156
pub enum WithinComponentLocation {
157
    Property(ComponentPropertyLocation),
158
    Component(ComponentLocation),
159
}
160

            
161
#[derive(Clone)]
162
pub struct CalendarPropertyError {
163
    pub message: String,
164
    pub severity: ICalendarErrorSeverity,
165
    pub location: Option<CalendarPropertyLocation>,
166
}
167

            
168
impl CalendarPropertyError {
169
188
    pub(super) fn many_from_param_errors(
170
188
        errors: Vec<ParamError>,
171
188
        index: usize,
172
188
        name: String,
173
188
    ) -> Vec<Self> {
174
188
        errors
175
188
            .into_iter()
176
206
            .map(|error| CalendarPropertyError {
177
36
                message: error.message,
178
36
                severity: error.severity,
179
36
                location: Some(CalendarPropertyLocation {
180
36
                    index,
181
36
                    name: name.clone(),
182
36
                    property_location: Some(WithinPropertyLocation::Param {
183
36
                        index: error.index,
184
36
                        name: error.name,
185
36
                    }),
186
36
                }),
187
206
            })
188
188
            .collect()
189
188
    }
190
}
191

            
192
#[derive(Clone)]
193
pub struct CalendarPropertyLocation {
194
    pub index: usize,
195
    pub name: String,
196
    pub property_location: Option<WithinPropertyLocation>,
197
}
198

            
199
#[derive(Clone)]
200
pub struct ComponentPropertyError {
201
    pub message: String,
202
    pub severity: ICalendarErrorSeverity,
203
    pub location: Option<ComponentPropertyLocation>,
204
}
205

            
206
impl ComponentPropertyError {
207
1580
    pub(super) fn many_from_param_errors(
208
1580
        errors: Vec<ParamError>,
209
1580
        index: usize,
210
1580
        name: String,
211
1580
    ) -> Vec<Self> {
212
1580
        errors
213
1580
            .into_iter()
214
1604
            .map(|error| ComponentPropertyError {
215
48
                message: error.message,
216
48
                severity: error.severity,
217
48
                location: Some(ComponentPropertyLocation {
218
48
                    index,
219
48
                    name: name.clone(),
220
48
                    property_location: Some(WithinPropertyLocation::Param {
221
48
                        index: error.index,
222
48
                        name: error.name,
223
48
                    }),
224
48
                }),
225
1604
            })
226
1580
            .collect()
227
1580
    }
228
}
229

            
230
#[derive(Clone)]
231
pub struct ComponentPropertyLocation {
232
    pub index: usize,
233
    pub name: String,
234
    pub property_location: Option<WithinPropertyLocation>,
235
}
236

            
237
#[derive(Clone)]
238
pub enum WithinPropertyLocation {
239
    Param { index: usize, name: String },
240
    Value,
241
}
242

            
243
pub struct ParamError {
244
    pub message: String,
245
    pub severity: ICalendarErrorSeverity,
246
    pub index: usize,
247
    pub name: String,
248
}