1use std::collections::HashMap;
2
3use crate::error::edf_error::EDFError;
4use crate::headers::annotation_list::AnnotationList;
5use crate::headers::edf_header::EDFHeader;
6use crate::headers::signal_header::SignalHeader;
7use crate::save::{SaveInstruction, SaveValue};
8
9#[derive(Debug, Default, Clone, PartialEq)]
10struct RecordLayout {
11 signal_map: HashMap<usize, SignalType>,
12 annotation_samples_count: Vec<usize>,
13}
14
15#[derive(Debug, Clone, PartialEq)]
16enum SignalType {
17 Samples(usize),
18 Annotation(usize),
19}
20
21#[derive(Debug, Clone, PartialEq)]
22pub struct Record {
23 layout: RecordLayout,
24 pub(crate) default_offset: f64,
25 pub raw_signal_samples: Vec<Vec<i16>>,
26 pub annotations: Vec<Vec<AnnotationList>>,
27}
28
29impl Record {
30 pub fn new(signal_headers: &Vec<SignalHeader>) -> Self {
31 let mut raw_signal_samples = Vec::new();
32 let mut annotations = Vec::new();
33 let mut annotation_samples_count = Vec::new();
34 let mut signal_map = HashMap::new();
35 for (i, signal) in signal_headers.iter().enumerate() {
36 if signal.is_annotation() {
37 signal_map.insert(i, SignalType::Annotation(annotations.len()));
38 annotation_samples_count.push(signal.samples_count);
39 annotations.push(Vec::new());
40 } else {
41 signal_map.insert(i, SignalType::Samples(raw_signal_samples.len()));
42 raw_signal_samples.push(vec![0; signal.samples_count]);
43 }
44 }
45
46 Self {
47 layout: RecordLayout {
48 signal_map,
49 annotation_samples_count,
50 },
51 default_offset: 0.0,
52 raw_signal_samples,
53 annotations,
54 }
55 }
56
57 pub fn patch_record(&mut self, instructions: &Vec<SaveInstruction>) -> Result<(), EDFError> {
58 if instructions.is_empty() {
59 return Ok(());
60 }
61
62 let mut signal_idx = instructions[0].index();
64 let mut instruction_idx = 0;
65 loop {
66 let Some(tr) = instructions.get(instruction_idx) else {
67 break;
68 };
69
70 match tr {
71 SaveInstruction::Remove(idx) if *idx == signal_idx => {
72 instruction_idx += 1;
73 self.remove_signal(*idx)?;
74 }
75 SaveInstruction::Insert(idx, SaveValue::Signal(value)) if *idx == signal_idx => {
76 instruction_idx += 1;
77 if value.is_annotation() {
78 self.insert_annotation(*idx, value.samples_count)?;
79 } else {
80 self.insert_signal_samples(*idx, value.samples_count)?;
81 }
82 }
83 SaveInstruction::Update(idx, SaveValue::Signal(value)) if *idx == signal_idx => {
84 signal_idx += 1;
85 instruction_idx += 1;
86 self.update_samples_count(*idx, value.samples_count)?;
87 }
88 _ => {
89 signal_idx += 1;
90 }
91 }
92 }
93
94 Ok(())
95 }
96
97 pub fn insert_signal_samples(
98 &mut self,
99 signal_index: usize,
100 samples_count: usize,
101 ) -> Result<(), EDFError> {
102 let insert_idx = (0..signal_index)
104 .filter(|i| {
105 self.layout
106 .signal_map
107 .get(&i)
108 .is_some_and(|s| matches!(s, SignalType::Samples(idx) if *idx < signal_index))
109 })
110 .count();
111
112 self.apply_index_change_samples(signal_index, insert_idx, 1);
114 self.layout
115 .signal_map
116 .insert(signal_index, SignalType::Samples(insert_idx));
117
118 self.raw_signal_samples
120 .insert(insert_idx, vec![0; samples_count]);
121
122 Ok(())
123 }
124
125 pub fn insert_annotation(
126 &mut self,
127 signal_index: usize,
128 samples_count: usize,
129 ) -> Result<(), EDFError> {
130 let insert_idx = (0..signal_index)
132 .filter(|i| {
133 self.layout.signal_map.get(&i).is_some_and(
134 |s| matches!(s, SignalType::Annotation(idx) if *idx < signal_index),
135 )
136 })
137 .count();
138
139 self.apply_index_change_annotation(signal_index, insert_idx, 1);
141 self.layout
142 .signal_map
143 .insert(signal_index, SignalType::Annotation(insert_idx));
144
145 self.layout
147 .annotation_samples_count
148 .insert(insert_idx, samples_count);
149 self.annotations.insert(insert_idx, Vec::new());
150
151 Ok(())
152 }
153
154 pub fn remove_signal(&mut self, signal_index: usize) -> Result<(), EDFError> {
155 match self.layout.signal_map.remove(&signal_index) {
156 Some(SignalType::Samples(idx)) => {
157 self.raw_signal_samples.remove(idx);
158 self.apply_index_change_samples(signal_index, idx, -1);
159 }
160 Some(SignalType::Annotation(idx)) => {
161 self.layout.annotation_samples_count.remove(idx);
162 self.annotations.remove(idx);
163 self.apply_index_change_annotation(signal_index, idx, -1);
164 }
165 _ => return Err(EDFError::ItemNotFound),
166 }
167
168 Ok(())
169 }
170
171 pub fn update_samples_count(
172 &mut self,
173 signal_index: usize,
174 samples_count: usize,
175 ) -> Result<(), EDFError> {
176 match self.layout.signal_map.get(&signal_index) {
177 Some(SignalType::Samples(idx)) => {
178 if let Some(count) = self.raw_signal_samples.get_mut(*idx) {
179 count.resize(samples_count, 0);
180 } else {
181 return Err(EDFError::ItemNotFound);
182 }
183 }
184 Some(SignalType::Annotation(idx)) => {
185 if let Some(count) = self.layout.annotation_samples_count.get_mut(*idx) {
186 *count = samples_count;
187 } else {
188 return Err(EDFError::ItemNotFound);
189 }
190 }
191 _ => return Err(EDFError::ItemNotFound),
192 }
193
194 Ok(())
195 }
196
197 pub fn set_annotation(
198 &mut self,
199 signal_index: usize,
200 annotations: Vec<AnnotationList>,
201 ) -> Result<(), EDFError> {
202 let Some(SignalType::Annotation(idx)) = self.layout.signal_map.get(&signal_index) else {
203 return Err(EDFError::ItemNotFound);
204 };
205
206 let Some(old_annotations) = self.annotations.get_mut(*idx) else {
207 return Err(EDFError::ItemNotFound);
208 };
209
210 *old_annotations = annotations;
211
212 Ok(())
213 }
214
215 pub fn set_samples(&mut self, signal_index: usize, samples: Vec<i16>) -> Result<(), EDFError> {
216 let Some(SignalType::Samples(idx)) = self.layout.signal_map.get(&signal_index) else {
217 return Err(EDFError::ItemNotFound);
218 };
219
220 let Some(old_samples) = self.raw_signal_samples.get_mut(*idx) else {
221 return Err(EDFError::ItemNotFound);
222 };
223
224 if old_samples.len() != samples.len() {
225 return Err(EDFError::InvalidSamplesCount);
226 }
227
228 *old_samples = samples;
229
230 Ok(())
231 }
232
233 pub fn get_digital_samples(&self, signal: &SignalHeader) -> Vec<Vec<i32>> {
234 self.raw_signal_samples.iter().map(|signals| {
235 signals.iter().map(|sample| {
236 (*sample as i32).clamp(signal.digital_minimum, signal.digital_maximum)
237 }).collect()
238 }).collect()
239 }
240
241 pub fn get_physical_samples(&self, signal: &SignalHeader) -> Vec<Vec<f64>> {
242 let range = (signal.physical_maximum - signal.physical_minimum) / (signal.digital_maximum - signal.digital_minimum) as f64;
243 let offset = signal.physical_maximum / range - signal.digital_maximum as f64;
244
245 self.raw_signal_samples.iter().map(|signals| {
246 signals.iter().map(|sample| {
247 let digital = *sample as f64;
248 let physical = range * (offset + digital);
249 physical.clamp(signal.physical_minimum, signal.physical_maximum)
250 }).collect()
251 }).collect()
252 }
253
254 fn apply_index_change_annotation(
255 &mut self,
256 signal_index: usize,
257 target_index: usize,
258 direction: i8,
259 ) {
260 let mut new = HashMap::new();
261 for (k, v) in self.layout.signal_map.drain() {
262 let new_global_index =
263 (k as i64 + direction as i64 * (k >= signal_index) as i64) as usize;
264 let value = if let SignalType::Annotation(idx) = v
265 && idx >= target_index
266 {
267 SignalType::Annotation((idx as i64 + direction as i64) as usize)
268 } else {
269 v
270 };
271 new.insert(new_global_index, value);
272 }
273 self.layout.signal_map = new;
274 }
275
276 fn apply_index_change_samples(
277 &mut self,
278 signal_index: usize,
279 target_index: usize,
280 direction: i8,
281 ) {
282 let mut new = HashMap::new();
283 for (k, v) in self.layout.signal_map.drain() {
284 let new_global_index =
285 (k as i64 + direction as i64 * (k >= signal_index) as i64) as usize;
286 let value = if let SignalType::Samples(idx) = v
287 && idx >= target_index
288 {
289 SignalType::Samples((idx as i64 + direction as i64) as usize)
290 } else {
291 v
292 };
293 new.insert(new_global_index, value);
294 }
295 self.layout.signal_map = new;
296 }
297
298 pub fn get_start_offset(&self) -> f64 {
304 self.annotations
305 .first()
306 .map(|tals| tals.iter().find(|a| a.is_time_keeping()).map(|a| a.onset))
307 .flatten()
308 .unwrap_or(self.default_offset)
309 }
310
311 pub fn serialize(&self) -> Result<Vec<u8>, EDFError> {
312 let mut result_buffer = vec![];
313
314 for signal_idx in 0..self.layout.signal_map.len() {
315 match self.layout.signal_map.get(&signal_idx) {
316 Some(SignalType::Annotation(idx)) => {
317 if let Some(annotation) = self.annotations.get(*idx)
318 && let Some(sample_count) = self.layout.annotation_samples_count.get(*idx)
319 {
320 let tals = annotation
321 .iter()
322 .map(|a| a.serialize())
323 .collect::<Vec<_>>()
324 .join("");
325 let mut tal_bytes = tals.as_bytes().to_vec();
326 tal_bytes.extend(vec![0; 2 * sample_count - tal_bytes.len()]);
327 result_buffer.extend(tal_bytes);
328 }
329 }
330 Some(SignalType::Samples(idx)) => {
331 if let Some(signal) = self.raw_signal_samples.get(*idx) {
332 result_buffer.extend(
333 &signal
334 .into_iter()
335 .map(|s| s.to_le_bytes())
336 .flatten()
337 .collect::<Vec<_>>(),
338 );
339 }
340 }
341 _ => {
342 panic!("Invalid record signal mapping index. This should not be possible")
343 }
344 }
345 }
346
347 Ok(result_buffer)
348 }
349
350 pub fn matches_signals(&self, signal_headers: &Vec<SignalHeader>) -> bool {
351 let actual_count = self.annotations.len() + self.raw_signal_samples.len();
353 if actual_count != signal_headers.len()
354 || actual_count != self.layout.signal_map.len()
355 || actual_count
356 != self
357 .layout
358 .signal_map
359 .keys()
360 .max()
361 .map(|k| *k + 1)
362 .unwrap_or(0)
363 {
364 return false;
365 }
366
367 for i in 0..actual_count {
369 match self.layout.signal_map.get(&i) {
370 Some(SignalType::Samples(idx)) => {
371 if !self
372 .raw_signal_samples
373 .get(*idx)
374 .is_some_and(|s| s.len() == signal_headers[i].samples_count)
375 {
376 return false;
377 }
378 }
379 Some(SignalType::Annotation(idx)) => {
380 if !self
381 .layout
382 .annotation_samples_count
383 .get(*idx)
384 .is_some_and(|c| *c == signal_headers[i].samples_count)
385 {
386 return false;
387 }
388 }
389 _ => return false,
390 }
391 }
392
393 true
394 }
395}
396
397#[derive(Debug, Default, Clone, PartialEq)]
398pub struct RelativeRecordData {
399 pub offset: f64,
400 pub raw_signal_samples: Vec<i16>,
401}
402
403impl RelativeRecordData {
404 pub fn new(offset: f64) -> Self {
405 Self {
406 offset,
407 raw_signal_samples: Vec::new(),
408 }
409 }
410
411 pub fn get_digital_samples(&self, signal: &SignalHeader) -> Vec<i32> {
412 self.raw_signal_samples.iter().map(|sample| {
413 (*sample as i32).clamp(signal.digital_minimum, signal.digital_maximum)
414 }).collect()
415 }
416
417 pub fn get_physical_samples(&self, signal: &SignalHeader) -> Vec<f64> {
418 let range = (signal.physical_maximum - signal.physical_minimum) / (signal.digital_maximum - signal.digital_minimum) as f64;
419 let offset = signal.physical_maximum / range - signal.digital_maximum as f64;
420
421 self.raw_signal_samples.iter().map(|sample| {
422 let digital = *sample as f64;
423 let physical = range * (offset + digital);
424 physical.clamp(signal.physical_minimum, signal.physical_maximum)
425 }).collect()
426 }
427}
428
429#[derive(Debug, Default, Clone, PartialEq)]
430pub struct SpanningRecord {
431 pub raw_signal_samples: Vec<Vec<RelativeRecordData>>,
432 pub annotations: Vec<Vec<AnnotationList>>,
433}
434
435impl SpanningRecord {
436 pub fn new(header: &EDFHeader) -> Self {
437 let signal_count = header.signals.iter().filter(|s| !s.is_annotation()).count();
438 Self {
439 raw_signal_samples: vec![Vec::new(); signal_count],
440 annotations: Vec::new(),
441 }
442 }
443
444 pub fn is_spanning_wait(&self) -> bool {
445 self.raw_signal_samples
446 .iter()
447 .all(|sp| sp.last().is_some_and(|data| data.raw_signal_samples.is_empty()))
448 }
449
450 pub fn remove_last_spanning_wait(&mut self) -> bool {
451 if self.is_spanning_wait() {
452 for signal in &mut self.raw_signal_samples {
453 signal.remove(signal.len() - 1);
454 }
455
456 return true;
457 }
458 return false;
459 }
460
461 pub fn insert_spanning_wait(&mut self, offset: f64) {
462 self.remove_last_spanning_wait();
463
464 if self
466 .raw_signal_samples
467 .first()
468 .map(|s| s.last())
469 .flatten()
470 .is_some_and(|s| s.offset == offset)
471 {
472 return;
473 }
474
475 for signal in &mut self.raw_signal_samples {
477 signal.push(RelativeRecordData::new(offset));
478 }
479 }
480
481 pub fn finish(&mut self) {
482 self.remove_last_spanning_wait();
483 }
486
487 pub fn extend_samples(&mut self, signal_index: usize, samples: Vec<i16>) {
488 if let Some(signal) = self.raw_signal_samples.get_mut(signal_index) {
489 if let Some(data) = signal.last_mut() {
490 data.raw_signal_samples.extend(samples);
491 }
492 }
493 }
494}