1use crate::error::{Error, Result};
2use crate::event::VEvent;
3use crate::vcalendar::VCalendar;
4
5#[derive(Debug, Clone, Copy, PartialEq)]
6pub enum SortKey {
7 Start,
8 End,
9 Summary,
10}
11
12pub fn sort_events(events: &[VEvent], keys: &[SortKey], descending: bool) -> Vec<VEvent> {
13 let mut sorted = events.to_vec();
14 sorted.sort_by(|a, b| {
15 let ord = keys
16 .iter()
17 .map(|key| match key {
18 SortKey::Start => a.dtstart.cmp(&b.dtstart),
19 SortKey::End => a.dtend.cmp(&b.dtend),
20 SortKey::Summary => a.summary.cmp(&b.summary),
21 })
22 .find(|o| o.is_ne())
23 .unwrap_or(std::cmp::Ordering::Equal);
24 if descending { ord.reverse() } else { ord }
25 });
26 sorted
27}
28
29pub fn remove_event_by_summary(cal: &VCalendar, summary: &str) -> Result<VCalendar> {
34 let remaining: Vec<VEvent> = cal
35 .events
36 .iter()
37 .filter(|e| e.summary != summary)
38 .cloned()
39 .collect();
40 if remaining.len() == cal.events.len() {
41 return Err(Error::parse(format!(
42 "No event found with summary: {summary}"
43 )));
44 }
45 Ok(VCalendar {
46 events: remaining,
47 ..cal.clone()
48 })
49}
50
51pub fn remove_events_by_indices(cal: &VCalendar, indices: &[usize]) -> Result<VCalendar> {
54 for &idx in indices {
55 if idx == 0 || idx > cal.events.len() {
56 return Err(Error::parse(format!(
57 "Index {idx} out of range (1-{})",
58 cal.events.len()
59 )));
60 }
61 }
62 let remaining: Vec<VEvent> = cal
63 .events
64 .iter()
65 .enumerate()
66 .filter(|(i, _)| !indices.contains(&(i + 1)))
67 .map(|(_, e)| e.clone())
68 .collect();
69 Ok(VCalendar {
70 events: remaining,
71 ..cal.clone()
72 })
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78 use crate::test_helpers::make_event;
79
80 fn vcal(events: Vec<VEvent>) -> VCalendar {
81 VCalendar {
82 events,
83 ..VCalendar::new("-//makeholiday//EN")
84 }
85 }
86
87 fn unsorted_events() -> Vec<VEvent> {
88 vec![
89 make_event("c", (2026, 5, 3), (2026, 5, 6), "憲法記念日"),
90 make_event("a", (2026, 1, 1), (2026, 1, 2), "元日"),
91 make_event("b", (2026, 2, 11), (2026, 2, 12), "建国記念の日"),
92 ]
93 }
94
95 #[test]
96 fn sort_by_start_asc() {
97 let sorted = sort_events(&unsorted_events(), &[SortKey::Start], false);
98 let summaries: Vec<_> = sorted.iter().map(|e| e.summary.as_str()).collect();
99 assert_eq!(summaries, vec!["元日", "建国記念の日", "憲法記念日"]);
100 }
101
102 #[test]
103 fn sort_by_start_desc() {
104 let sorted = sort_events(&unsorted_events(), &[SortKey::Start], true);
105 let summaries: Vec<_> = sorted.iter().map(|e| e.summary.as_str()).collect();
106 assert_eq!(summaries, vec!["憲法記念日", "建国記念の日", "元日"]);
107 }
108
109 #[test]
110 fn sort_by_end_asc() {
111 let sorted = sort_events(&unsorted_events(), &[SortKey::End], false);
112 let summaries: Vec<_> = sorted.iter().map(|e| e.summary.as_str()).collect();
113 assert_eq!(summaries, vec!["元日", "建国記念の日", "憲法記念日"]);
114 }
115
116 #[test]
117 fn sort_by_summary_asc() {
118 let sorted = sort_events(&unsorted_events(), &[SortKey::Summary], false);
119 let summaries: Vec<_> = sorted.iter().map(|e| e.summary.as_str()).collect();
120 assert_eq!(summaries, vec!["元日", "建国記念の日", "憲法記念日"]);
121 }
122
123 #[test]
124 fn sort_by_summary_desc() {
125 let sorted = sort_events(&unsorted_events(), &[SortKey::Summary], true);
126 let summaries: Vec<_> = sorted.iter().map(|e| e.summary.as_str()).collect();
127 assert_eq!(summaries, vec!["憲法記念日", "建国記念の日", "元日"]);
128 }
129
130 #[test]
131 fn sort_multi_key() {
132 let events = vec![
133 make_event("a", (2026, 1, 1), (2026, 1, 2), "B休日"),
134 make_event("b", (2026, 1, 1), (2026, 1, 2), "A休日"),
135 make_event("c", (2026, 2, 1), (2026, 2, 2), "C休日"),
136 ];
137 let sorted = sort_events(&events, &[SortKey::Start, SortKey::Summary], false);
138 let summaries: Vec<_> = sorted.iter().map(|e| e.summary.as_str()).collect();
139 assert_eq!(summaries, vec!["A休日", "B休日", "C休日"]);
140 }
141
142 #[test]
143 fn remove_by_summary() {
144 let cal = vcal(vec![
145 make_event("a", (2026, 1, 1), (2026, 1, 2), "元日"),
146 make_event("b", (2026, 2, 11), (2026, 2, 12), "建国記念の日"),
147 ]);
148 let updated = remove_event_by_summary(&cal, "元日").unwrap();
149 assert_eq!(updated.events.len(), 1);
150 assert_eq!(updated.events[0].summary, "建国記念の日");
151 }
152
153 #[test]
154 fn remove_by_summary_not_found() {
155 let cal = vcal(vec![make_event("a", (2026, 1, 1), (2026, 1, 2), "元日")]);
156 let result = remove_event_by_summary(&cal, "存在しない");
157 assert!(result.is_err());
158 }
159
160 #[test]
161 fn remove_multiple_by_indices() {
162 let cal = vcal(vec![
163 make_event("a", (2026, 1, 1), (2026, 1, 2), "A"),
164 make_event("b", (2026, 2, 1), (2026, 2, 2), "B"),
165 make_event("c", (2026, 3, 1), (2026, 3, 2), "C"),
166 make_event("d", (2026, 4, 1), (2026, 4, 2), "D"),
167 ]);
168 let updated = remove_events_by_indices(&cal, &[2, 4]).unwrap();
169 let summaries: Vec<_> = updated.events.iter().map(|e| e.summary.as_str()).collect();
170 assert_eq!(summaries, vec!["A", "C"]);
171 }
172}