aemo_mdff/
nem12.rs

1use nom::{
2    branch::{alt,permutation}, bytes::complete::tag, character::complete::{alpha1, alphanumeric1, digit1, multispace0}, combinator::{map, opt, peek, recognize}, error::Error, multi::separated_list1 as separated_list, number::complete::double, sequence::{pair, preceded, terminated}, Err, IResult, InputTake, Needed
3};
4
5use chrono::{NaiveDateTime,NaiveDate};
6use record::{B2BDetails, EndOfData, Header, IntervalData, IntervalEvent, NMIDataDetails};
7use std::{str, sync::Mutex};
8
9use crate::common::*;
10
11#[derive(Clone,Debug,PartialEq)]
12pub struct NEM12<'a> {
13    header: record::Header<'a>,
14    nmi_data_details: Vec<record::NMIDataDetails<'a>>
15}
16
17fn parse_nmi_data_details<'a>(input:Input<'a>) -> IResult<Input,NMIDataDetails> {
18    let (input, mut nmi_details) = terminated(NMIDataDetails::parse,rec_separator)(input)?;
19    let interval_data_len = 1440 / nmi_details.interval_length;
20    let (input_pre_b2b,interval_data) = opt(separated_list(rec_separator, parse_interval_data(interval_data_len)))(input)?;
21    let (input,_) = rec_separator(input_pre_b2b)?;
22
23    nmi_details.interval_data_vec = interval_data;
24
25    if let (input,Some(b2b_details)) = opt(separated_list(rec_separator, B2BDetails::parse))(input)? {
26        nmi_details.b2b_details = Some(b2b_details);
27        Ok((input,nmi_details))
28    } else {
29        Ok((input_pre_b2b,nmi_details))
30    }
31    
32}
33
34fn parse_interval_data<'a>(capacity: usize) -> impl FnMut(Input<'a>) -> IResult<Input<'a>,IntervalData<'a>> {
35    move |input: Input<'a>| {
36        let (input_before_events, mut interval_data) = IntervalData::parse(capacity,input)?;
37        let (input, _) = rec_separator(input_before_events)?;
38        let (input, interval_events) = opt(separated_list(rec_separator, IntervalEvent::parse))(input)?;
39        interval_data.interval_events = interval_events;
40
41        if interval_data.interval_events.is_some() {
42            Ok((input,interval_data))
43        } else {
44            Ok((input_before_events,interval_data))
45        }
46    }
47}
48
49impl <'a>NEM12<'a> {
50    fn new(header: Header<'a>, nmi_data_details: Vec<NMIDataDetails<'a>>) -> Self {
51        NEM12 {
52            header,
53            nmi_data_details
54        }
55    }
56
57    fn from_str(input: Input<'a>) -> Result<NEM12<'a>,Err<Error<Input<'a>>>> {
58        let strict = true;
59        let (input,header) = Header::parse(input)?;
60        let (input,_) = rec_separator(input)?;
61        let (input,nmi_data_details) = separated_list(rec_separator, parse_nmi_data_details)(input)?;
62        let (input,_) = rec_separator(input)?;
63        let (_input,_) = EndOfData::parse(input)?;
64
65        Ok(NEM12 {
66            header,
67            nmi_data_details
68        })
69    }
70}
71
72struct Parser<'a> {
73    src: Input<'a>,
74    iter: std::iter::Peekable<std::iter::Enumerate<str::Lines<'a>>>,
75    data: Option<NEM12<'a>>,
76    finished: bool,
77    ctx: Mutex<(usize,)>,
78    // ctx: (usize,),
79}
80
81impl <'a>Parser<'a> {
82
83    fn new(src: Input<'a>) -> Self {
84        let parser = Parser {
85            src,
86            iter: src.lines().enumerate().peekable(),
87            data: None,
88            finished: false,
89            ctx:Mutex::new((0,)),
90            // ctx:(0,),
91        };
92
93        parser
94    }
95
96    fn parse_line(&mut self) -> Result<Option<record::Kind>,(&'static str,usize,Err<Error<Input<'a>>>)> {
97        if let Some((line_no,line)) = self.iter.next() {
98            // println!("PARSING {}: '{}'",line_no,line);
99            let res = alt((
100                map(record::Header::parse, |o| Some(record::Kind::Header(o))),
101                map(record::NMIDataDetails::parse, |o| {
102                    let mut mutex = self.ctx.lock().unwrap();
103                    mutex.0 = 1440usize / o.interval_length;
104                    Some(record::Kind::NMIDataDetails(o))
105                }),
106                map(|input|record::IntervalData::parse(self.ctx.lock().unwrap().0,input),
107                    |o| { Some(record::Kind::IntervalData(o)) }),
108                map(record::IntervalEvent::parse, |o| Some(record::Kind::IntervalEvent(o))),
109                map(record::B2BDetails::parse, |o| Some(record::Kind::B2BDetails(o))),
110                map(record::EndOfData::parse, |o| Some(record::Kind::EndOfData(o))),
111            ))(line.into())
112                .map_err(|err| {
113                    match err {
114                        Err::Error(sentinel) => ("Error parsing line: ",line_no+1,Err::Error(sentinel)),
115                        Err::Failure(sentinel) => ("Failed to parse line: ",line_no+1,Err::Failure(sentinel)),
116                        Err::Incomplete(needed) => match needed {
117                            Needed::Size(sz) => ("Failed to parse line: ",sz.into(),err),
118                            Needed::Unknown => ("Failed to parse line: ",line_no+1,err)
119                        }
120                    }
121                });
122            match res {
123                Ok(r) => Ok(r.1),
124                Err(e) => Err(e),
125            }
126
127            // return Ok(Some(res.1));
128        } else {
129            match !self.finished {
130                true => {
131                    self.finished = true;
132                    Ok(None)
133                }
134                false => Err(("Error: parser consumed all input",0,nom::Err::Incomplete(Needed::Unknown)))
135            }
136        }
137    }
138}
139
140pub mod file {
141    use super::*;
142
143    #[cfg(test)]
144    mod tests {
145        use super::*;
146        use pretty_assertions::{assert_eq};
147
148        const MULTIPLE_METERS_STR: &'static str = "100,NEM12,200402070911,MDA1,Ret1\n\
149        200,NCDE001111,E1B1Q1E2,1,E1,N1,METSER123,Wh,15,\n\
150        300,20031204,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,A,,,20031206011132,20031207011022\n\
151        300,20031205,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,A,,,20031206011132,20031207011022\n\
152        200,NCDE001111,E1B1Q1E2,2,B1,N1,METSER123,Wh,15,\n\
153        300,20031204,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,A,,,20031206011132,20031207011022\n\
154        300,20031205,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,A,,,20031206011132,20031207011022\n\
155        200,NCDE001111,E1B1Q1E2,3,Q1,,METSER123,VArh,15,\n\
156        300,20031204,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,A,,,20031206011155,\n\
157        300,20031205,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,A,,,20031206011155,\n\
158        200,NCDE001111,E1B1Q1E2,4,E2,N2,METSER456,Wh,15,\n\
159        300,20031204,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,A,,,20031206011140,20031207011022\n\
160        300,20031205,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,A,,,20031206011140,20031207011022\n\
161        200,NDDD001888,B1K2,1,B1,N1,METSER991,Wh,15,\n\
162        300,20031204,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,A,,,20031206011145,20031207011022\n\
163        300,20031205,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,A,,,20031206011145,20031207011022\n\
164        200,NDDD001888,B1K2,2,K2,,METSER992,VArh,15,\n\
165        300,20031204,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,A,,,20031206011155,\n\
166        300,20031205,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,A,,,20031206011155,\n\
167        900";
168
169        const DATADETAILS_ROWS_STR: &'static str = "200,NCDE001111,E1B1Q1E2,1,E1,N1,METSER123,Wh,15,\n\
170        300,20031204,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,A,,,20031206011132,20031207011022\n\
171        300,20031205,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,A,,,20031206011132,20031207011022\n\
172        ";
173
174        const NEM12_WITH_QUALITY: &'static str = "100,NEM12,200404201300,MDA1,Ret1\n\
175        200,CCCC123456,E1,001,E1,N1,METSER123,kWh,30,\n\
176        300,20040417,18.023,19.150,17.592,24.155,18.568,22.304,19.222,19.032,19.090,22.237,24.350,22.274,20.193,16.615,19.575,20.391,16.459,20.527,21.438,19.327,21.424,16.656,17.616,18.416,16.666,19.961,18.120,18.023,18.588,21.759,17.841,19.548,18.486,21.391,15.656,16.634,16.377,14.246,17.451,15.742,18.038,18.470,14.936,17.987,15.751,19.750,16.202,14.733,V,,,20040418203500,20040419003500\n\
177        400,1,20,F14,76,\n\
178        400,21,24,A,,\n\
179        400,25,48,S14,1,\n\
180        900\n\
181        ";
182
183        #[test]
184        fn get_nmi_data_details_parser() {
185            let (input,nmi_data_details) = record::NMIDataDetails::parse(DATADETAILS_ROWS_STR.into()).unwrap();
186            
187            let capacity = 1440 / nmi_data_details.interval_length;
188            let (input,_) = preceded(rec_separator,|i|{record::IntervalData::parse(capacity, i)})(input).unwrap();
189            let (input,_) = preceded(rec_separator,|i|{record::IntervalData::parse(capacity, i)})(input).unwrap();
190            assert_eq!(input.into_fragment(),"\n");
191
192            let (input, nmi_data_details) = parse_nmi_data_details(DATADETAILS_ROWS_STR.into()).unwrap();
193            // TODO: Write test to compare output
194        }
195
196        #[test]
197        fn get_nmi_with_data_quality() {
198            let nmi_data_details = record::NMIDataDetails {
199                nmi: "CCCC123456".into(),
200                nmi_configuration: "E1".into(),
201                register_id: "001".into(),
202                nmi_suffix: "E1".into(),
203                mdm_data_stream_id: Some("N1".into()),
204                meter_serial_number: "METSER123".into(),
205                uom: "KWH".into(),
206                interval_length: 30usize,
207                next_scheduled_read_date: None,
208                interval_data_vec: Some(vec![IntervalData {
209                    interval_date: NaiveDate::from_ymd(2004,04,17),
210                    interval_value: vec![18.023, 19.15, 17.592, 24.155, 18.568, 22.304, 19.222, 19.032, 19.09, 22.237, 24.35, 22.274, 20.193, 16.615, 19.575, 20.391, 16.459, 20.527, 21.438, 19.327, 21.424, 16.656, 17.616, 18.416, 16.666, 19.961, 18.12, 18.023, 18.588, 21.759, 17.841, 19.548, 18.486, 21.391, 15.656, 16.634, 16.377, 14.246, 17.451, 15.742, 18.038, 18.47, 14.936, 17.987, 15.751, 19.75, 16.202, 14.733],
211                    quality_method: "V".into(),
212                    reason_code: None,
213                    reason_description: None,
214                    update_datetime: NaiveDateTime::parse_from_str("2004-04-18T20:35:00","%Y-%m-%dT%H:%M:%S").unwrap(),
215                    msats_load_datetime: Some(NaiveDateTime::parse_from_str("2004-04-19T00:35:00","%Y-%m-%dT%H:%M:%S").unwrap()),
216                    interval_events: Some(vec![
217                        IntervalEvent::parse("400,1,20,F14,76,\n".into()).map(|(_,o)|o).unwrap(),
218                        IntervalEvent::parse("400,21,24,A,,\n".into()).map(|(_,o)|o).unwrap(),
219                        IntervalEvent::parse("400,25,48,S14,1,\n".into()).map(|(_,o)|o).unwrap(),
220                    ])
221                }]),
222                b2b_details: None,
223            };
224            let nem12_test = NEM12 {
225                header: record::Header::new(
226                    "NEM12".into(),
227                    NaiveDate::from_ymd(2004,04,20).and_hms(13,0,0),
228                    "MDA1".into(),
229                    "Ret1".into()
230                ),
231                nmi_data_details: vec![nmi_data_details],
232            };
233            let nem12_obj = NEM12::from_str(NEM12_WITH_QUALITY.into());
234            assert_eq!(Ok(nem12_test),nem12_obj)
235        }
236
237        #[test]
238        fn multiple_meters_from_str() {
239            let _nem12_obj = NEM12::from_str(MULTIPLE_METERS_STR.into()).unwrap();
240        }
241
242        #[test]
243        fn multiple_meters() {
244
245            let mut parser = Parser::new(MULTIPLE_METERS_STR.into());
246
247            for _ in 1..20 {
248                parser.parse_line().unwrap();
249            }
250
251            assert_eq!(parser.parse_line(),Ok(Some(record::Kind::EndOfData(record::EndOfData{}))));
252            assert_eq!(parser.parse_line(),Ok(None));
253            assert_eq!(parser.parse_line(),Err(("Error: parser consumed all input",0,nom::Err::Incomplete(Needed::Unknown))));
254        }
255
256        #[test]
257        fn nem12_from_str() {
258            let _nem12_obj = NEM12::from_str(MULTIPLE_METERS_STR.into());
259            if let Err(e) = _nem12_obj {
260                println!("{:?}",e);
261            }
262            // _nem12_obj.unwrap();
263        }
264    }
265}
266
267pub mod record {
268    use nom::multi::many_m_n;
269
270    use super::*;
271
272    #[derive(Clone,Debug,PartialEq)]
273    pub enum Kind<'a> {
274        Header(Header<'a>),
275        NMIDataDetails(NMIDataDetails<'a>),
276        IntervalData(IntervalData<'a>),
277        IntervalEvent(IntervalEvent<'a>),
278        B2BDetails(B2BDetails<'a>),
279        EndOfData(EndOfData)
280    }
281
282    // Header record (100)
283    #[derive(Clone,Debug)]
284    pub struct Header<'a> {
285        format: Input<'a>,
286        created: NaiveDateTime,
287        from_participant: Input<'a>,
288        to_participant: Input<'a>,
289    }
290
291    impl <'a>PartialEq for Header<'a> {
292        fn eq(&self, other: &Self) -> bool {
293            self.format.into_fragment() == other.format.into_fragment() &&
294            self.created == other.created &&
295            self.from_participant.into_fragment() == other.from_participant.into_fragment() &&
296            self.to_participant.into_fragment() == other.to_participant.into_fragment()
297        }
298    }
299
300    impl <'a>Eq for Header<'a> { }
301
302    impl <'a>Header<'a> {
303        pub fn new(format:Input<'a>, created: NaiveDateTime, from_participant: Input<'a>, to_participant: Input<'a>) -> Self {
304            Header {
305                format,
306                created,
307                from_participant,
308                to_participant
309            }
310        }
311
312        pub fn parse(input: Input) -> IResult<Input,Header> {
313            let (input, _) = tag("100,")(input)?;
314            let (input, format) = alt((tag("NEM12"),tag("NEM13")))(input)?;
315            let (input, _) = tag(",")(input)?;
316            let (input, created) = datetime_12(input)?;
317            let (input, _) = tag(",")(input)?;
318            let (input, from_participant) = section_of_max_length(alphanumeric1,10)(input)?;
319            let (input, _) = tag(",")(input)?;
320            let (input, to_participant) = section_of_max_length(alphanumeric1,10)(input)?;
321    
322            let header = Header::new(
323                format,
324                created,
325                from_participant,
326                to_participant
327            );
328    
329            Ok((input,header))
330        }
331    }
332
333    // NMI data details record (200)
334    #[derive(Clone,Debug)]
335    pub struct NMIDataDetails<'a> {
336        pub nmi: Input<'a>,
337        pub nmi_configuration: Input<'a>,
338        pub register_id: Input<'a>,
339        pub nmi_suffix: Input<'a>,
340        pub mdm_data_stream_id: Option<Input<'a>>,
341        pub meter_serial_number: Input<'a>,
342        pub uom: Input<'a>,
343        pub interval_length: usize,
344        pub next_scheduled_read_date: Option<NaiveDate>,
345        pub interval_data_vec: Option<Vec<IntervalData<'a>>>,
346        pub b2b_details: Option<Vec<B2BDetails<'a>>>,
347    }
348
349    impl <'a>PartialEq for NMIDataDetails<'a> {
350        fn eq(&self, other: &Self) -> bool {
351            self.nmi.into_fragment() == other.nmi.into_fragment() &&
352            self.nmi_configuration.into_fragment() == other.nmi_configuration.into_fragment() &&
353            self.register_id.into_fragment() == other.register_id.into_fragment() &&
354            self.nmi_suffix.into_fragment() == other.nmi_suffix.into_fragment() &&
355            self.mdm_data_stream_id.map(|o| o.into_fragment()) == other.mdm_data_stream_id.map(|o| o.into_fragment()) &&
356            self.meter_serial_number.into_fragment() == other.meter_serial_number.into_fragment() &&
357            self.uom.into_fragment().to_owned().to_lowercase() == other.uom.into_fragment().to_owned().to_lowercase() &&
358            self.interval_length == other.interval_length &&
359            self.next_scheduled_read_date == other.next_scheduled_read_date &&
360            self.interval_data_vec == other.interval_data_vec &&
361            self.b2b_details == other.b2b_details
362        }
363    }
364
365    impl <'a>Eq for NMIDataDetails<'a> { }
366
367    impl <'a>NMIDataDetails<'a> {
368        pub fn parse(input: Input) -> IResult<Input,NMIDataDetails> {
369            let (input, _) = tag("200,")(input)?;
370            let (input, nmi) = section_of_exact_length(alphanumeric1, 10)(input)?;
371            let (input, _) = tag(",")(input)?;
372            let (input, nmi_configuration) = section_of_max_length(alphanumeric1, 240)(input)?;
373            let (input, _) = tag(",")(input)?;
374            let (input, register_id) = section_of_max_length(alphanumeric1, 10)(input)?;
375            let (input, _) = tag(",")(input)?;
376            let (input, nmi_suffix) = section_of_exact_length(alphanumeric1, 2)(input)?;
377            let (input, _) = tag(",")(input)?;
378            let (input, mdm_data_stream_id) = optional_field(section_of_exact_length(alphanumeric1, 2),",")(input)?;
379            let (input, _) = tag(",")(input)?;
380            let (input, meter_serial_number) = section_of_max_length(alphanumeric1, 12)(input)?;
381            let (input, _) = tag(",")(input)?;
382            let (input, uom) = section_of_max_length(alphanumeric1, 5)(input)?;
383            let (input, _) = tag(",")(input)?;
384            let (input, interval_length) = section_of_exact_length(digit1, 2)(input).map(|(input,val)| (input,val.parse::<usize>().unwrap()))?;
385            let (input, _) = tag(",")(input)?;
386            let (input, next_scheduled_read_date) = match date_8(input){
387                Ok(d) => Ok((d.0,Some(d.1))),
388                Err(nom::Err::Error(_)) => {
389                    match peek(alt((eof,tag("\n"))))(input) { // TODO: Add alt(eof,tag) to optional_field
390                        Ok((input,_)) => Ok((input,None)),
391                        Err(nom::Err::Error(e)) => {
392                            return Err(nom::Err::Error(e))
393                        }
394                        x => { println!("'{:?}'", x); panic!("This should never happen") }
395                    }
396                },
397                x => { println!("{:?}", x); panic!("This should never happen") }
398            }?;
399    
400            // let interval_data_length = 1440usize / interval_length;
401            // let (input, interval_data_vec) = separated_list0(
402            //     rec_separator, 
403            //     |input| record::IntervalData::parse(interval_data_length, input)
404            // )(input)?;
405    
406            let nmi_data_details  = NMIDataDetails {
407                nmi,
408                nmi_configuration,
409                register_id,
410                nmi_suffix,
411                mdm_data_stream_id,
412                meter_serial_number,
413                uom,
414                interval_length,
415                next_scheduled_read_date,
416                interval_data_vec: None,
417                b2b_details: None,
418            };
419    
420            Ok((input,nmi_data_details))
421            }
422    }
423
424    // Interval data record (300)
425    #[derive(Clone,Debug)]
426    pub struct IntervalData<'a> {
427        pub interval_date: NaiveDate,
428        pub interval_value: Vec<f64>,
429        pub quality_method: Input<'a>,
430        pub reason_code: Option<Input<'a>>,
431        pub reason_description: Option<Input<'a>>,
432        pub update_datetime: NaiveDateTime,
433        pub msats_load_datetime: Option<NaiveDateTime>,
434        pub interval_events: Option<Vec<IntervalEvent<'a>>>
435    }
436
437    impl <'a>PartialEq for IntervalData<'a> {
438        fn eq(&self, other: &Self) -> bool {
439            self.interval_date == other.interval_date &&
440            self.interval_value == other.interval_value &&
441            self.quality_method.into_fragment() == other.quality_method.into_fragment() &&
442            self.reason_code.map(|o| o.into_fragment()) == other.reason_code.map(|o| o.into_fragment()) &&
443            self.reason_description.map(|o| o.into_fragment()) == other.reason_description.map(|o| o.into_fragment()) &&
444            self.update_datetime == other.update_datetime &&
445            self.msats_load_datetime == other.msats_load_datetime &&
446            self.interval_events == other.interval_events
447        }
448    }
449
450    impl <'a>Eq for IntervalData<'a> { }
451
452    impl <'a>IntervalData<'a> {
453        pub fn parse(capacity: usize, input: Input<'a>) -> IResult<Input<'a>,IntervalData<'a>> {
454            interval_data(capacity, input)
455        }
456    }
457
458    fn interval_data<'a>(capacity: usize, input: Input<'a>) -> IResult<Input<'a>,IntervalData<'a>> {
459        let (input, _) = tag("300,")(input)?;
460        let (input, interval_date) = date_8(input)?;
461        let (input, interval_value) = many_m_n(capacity,capacity,preceded(tag(","),double))(input)?;
462
463        // if let Some(details) = nmi_data_details_rec {
464        //     if (1440 / details.interval_length) != interval_value.len() {
465        //         return Err(nom::Err::Error(error::make_error(input,error::ErrorKind::SeparatedList)))
466        //     }
467        // }
468
469        let (input, _) = tag(",")(input)?;
470        let (input, quality_method) = section_of_max_length(alpha1, 3)(input)?;
471        let (input, _) = tag(",")(input)?;
472        let (input, reason_code) = optional_field(section_of_max_length(digit1, 3),",")(input)?;
473
474        let (input, _) = tag(",")(input)?;
475        let (input, reason_description) = optional_field(section_of_max_length(alphanumeric1, 240),",")(input)?;
476
477        let (input, _) = tag(",")(input)?;
478        let (input, update_datetime) = datetime_14(input)?;
479        let (input, _) = tag(",")(input)?;
480        let (input, msats_load_datetime) = opt(datetime_14)(input)?;
481
482        // // Get Event Codes (400 recs)
483        // let (input,_) = rec_separator(input)?;
484        // let (input,interval_events): (Input,Vec<record::IntervalEvent>) = separated_list0(rec_separator,record::IntervalEvent::parse)(input)?;
485
486        let interval_data = IntervalData {
487            interval_date,
488            interval_value,
489            quality_method,
490            reason_code,
491            reason_description,
492            update_datetime,
493            msats_load_datetime,
494            interval_events: None
495        };
496
497        Ok((input,interval_data))
498    }
499
500    // Interval event record (400)
501    #[derive(Clone,Debug)]
502    pub struct IntervalEvent<'a> {
503        pub start_interval: Input<'a>,
504        pub end_interval: Input<'a>,
505        pub quality_method: Input<'a>,
506        pub reason_code: Option<Input<'a>>,
507        pub reason_description: Option<Input<'a>>,
508    }
509
510    impl <'a>PartialEq for IntervalEvent<'a> {
511        fn eq(&self, other: &Self) -> bool {
512            self.start_interval.into_fragment() == other.start_interval.into_fragment() &&
513            self.end_interval.into_fragment() == other.end_interval.into_fragment() &&
514            self.quality_method.into_fragment() == other.quality_method.into_fragment() &&
515            self.reason_code.map(|o| o.into_fragment()) == other.reason_code.map(|o| o.into_fragment()) &&
516            self.reason_description.map(|o| o.into_fragment()) == other.reason_description.map(|o| o.into_fragment())
517        }
518    }
519
520    impl <'a>Eq for IntervalEvent<'a> { }
521
522    impl <'a>IntervalEvent<'a> {
523        pub fn parse(input: Input<'a>) -> IResult<Input<'a>,IntervalEvent> {
524            interval_event(input)
525        }
526    }
527
528    fn interval_event<'a>(input: Input<'a>) -> IResult<Input<'a>,IntervalEvent<'a>> {
529        let (input, _) = tag("400,")(input)?;
530        let (input, start_interval) = section_of_max_length(digit1,4)(input)?;
531        let (input, _) = tag(",")(input)?;
532        let (input, end_interval) = section_of_max_length(digit1,4)(input)?;
533        let (input, _) = tag(",")(input)?;
534        let (input, quality_method) = section_of_max_length(alphanumeric1,3)(input)?;
535        let (input, _) = tag(",")(input)?;
536        let (input, reason_code) = optional_field(section_of_max_length(digit1,3),",")(input)?;
537        let (input, _) = tag(",")(input)?;
538        let (input, reason_description) = optional_field(section_of_max_length(alphanumeric1,24),"\n")(input)?;
539
540        let interval_event = IntervalEvent {
541            start_interval,
542            end_interval,
543            quality_method,
544            reason_code,
545            reason_description
546        };
547
548        Ok((input,interval_event))
549    }
550
551    // B2B details record (500)
552    #[derive(Clone,Debug)]
553    pub struct B2BDetails<'a> {
554        pub trans_code: Input<'a>,
555        pub ret_service_order: Input<'a>,
556        pub read_datetime: NaiveDateTime,
557        pub index_read: Input<'a>,
558    }
559
560    impl <'a>PartialEq for B2BDetails<'a> {
561        fn eq(&self, other: &Self) -> bool {
562            self.trans_code.into_fragment() == other.trans_code.into_fragment() &&
563            self.ret_service_order.into_fragment() == other.ret_service_order.into_fragment() &&
564            self.read_datetime == other.read_datetime &&
565            self.index_read.into_fragment() == other.index_read.into_fragment()
566        }
567    }
568
569    impl <'a>Eq for B2BDetails<'a> { }
570
571    impl B2BDetails<'_> {
572        pub fn parse(input: Input) -> IResult<Input,B2BDetails> {
573            b2b_details(input)
574        }
575    }
576
577    fn b2b_details<'a>(input: Input<'a>) -> IResult<Input<'a>,B2BDetails<'a>> {
578        let (input, _) = tag("500,")(input)?;
579        let (input, trans_code) = section_of_exact_length(alpha1,1)(input)?;
580        let (input, _) = tag(",")(input)?;
581        let (input, ret_service_order) = section_of_max_length(alphanumeric1,15)(input)?;
582        let (input, _) = tag(",")(input)?;
583        let (input, read_datetime) = datetime_14(input)?;
584        let (input, _) = tag(",")(input)?;
585        let (input, index_read) = section_of_max_length(
586            move |i| recognize(permutation((digit1,opt(pair(tag("."),digit1)))))(i)
587        ,15)(input)?;
588
589        let b2b_details = B2BDetails {
590            trans_code,
591            ret_service_order,
592            read_datetime,
593            index_read
594        };
595
596        Ok((input,b2b_details))
597    }
598
599    // End of data (900)
600    #[derive(Clone,Debug,PartialEq)]
601    pub struct EndOfData {}
602
603    impl EndOfData {
604        pub fn parse(input: Input) -> IResult<Input,EndOfData> {
605            end_of_data(input)
606        }
607    }
608
609    fn end_of_data(input: Input) -> IResult<Input,EndOfData> {
610        let (input, _) = tag("900")(input)?;
611        let (input, _) = multispace0(input)?; // TODO: Should this be removed?
612        Ok((input,EndOfData {}))
613    }
614
615    #[cfg(test)]
616    mod tests {
617        use std::borrow::Borrow;
618
619        use super::{record,Input};
620        use nom::error;
621        use chrono::{NaiveDate};
622    
623        #[test]
624        fn header_100() {
625            let date = NaiveDate::from_ymd(2004,5,1).and_hms(11, 35, 0);
626            let header = record::Header::new (
627                "NEM12".into(),
628                date.clone(),
629                "MDA1".into(),
630                "Ret1".into()
631            );
632    
633            let raw = "100,NEM12,200405011135,MDA1,Ret1\n";
634    
635            let res = record::Header::parse(raw.into());
636    
637            assert_eq!(res.map(|(r,v)| (r.into_fragment(),v)),
638                Ok(("\n",header))
639            );
640    
641            let header = record::Header::new (
642                "NEM12".into(),
643                date.clone().into(),
644                "0123456789".into(),
645                "Ret1".into()
646            );
647    
648            let raw = "100,NEM12,200405011135,0123456789,Ret1\n";
649    
650            let res = record::Header::parse(raw.into()); /* {
651                Ok(o) => o,
652                Err(e) => { println!("{:?}",e); panic!("Failed") }
653            }; */
654    
655            assert_eq!(res.map(|(r,v)| (r.into_fragment(),v)),
656                Ok(("\n",header))
657            );
658    
659            let raw = "100,NEM12,200405011135,12345678910,Ret1\n";
660    
661            let res = match record::Header::parse(raw.into())
662            .map(|(r,v)| (r.into_fragment(),v)) {
663                Ok(o) => { println!("{:?}",o); panic!("Failed") },
664                Err(nom::Err::Error(e)) => { (e.input.into_fragment(),error::ErrorKind::Verify) }, //NOTE: must accomodate custom errors somehow
665                Err(nom::Err::Incomplete(_)) |
666                Err(nom::Err::Failure(_)) => panic!("This should never happen")
667            };
668    
669            assert_eq!(res, ("12345678910,Ret1\n",error::ErrorKind::Verify));
670        }
671    
672        #[test]
673        fn nmi_data_details_200() {
674            let nmi_data_details = record::NMIDataDetails {
675                nmi: "VABD000163".into(),
676                nmi_configuration: "E1Q1".into(),
677                register_id: "1".into(),
678                nmi_suffix: "E1".into(),
679                mdm_data_stream_id: Some("N1".into()),
680                meter_serial_number: "METSER123".into(),
681                uom: "KWH".into(),
682                interval_length: 30usize,
683                next_scheduled_read_date: None,
684                interval_data_vec: None,
685                b2b_details: None,
686            };
687    
688            let raw = "200,VABD000163,E1Q1,1,E1,N1,METSER123,KWH,30,\n";
689    
690            let res = record::NMIDataDetails::parse(raw.into());
691    
692            assert_eq!(res.map(|(i,v)|(i.into_fragment(),v)),Ok(("\n",nmi_data_details)));
693    
694            let raw = "200,VABD000163,E1Q1,1,E1,N1,METSER123,kWh,30,1234\n";
695    
696            let res = record::NMIDataDetails::parse(raw.into());
697    
698            assert_eq!(res.map(|(i,v)|(i.into_fragment(),v)).map_err(|e| {
699                match e {
700                    nom::Err::Incomplete(e)=> nom::Err::Incomplete(e),
701                    nom::Err::Error(e) => nom::Err::Error(e.input.into_fragment()),
702                    nom::Err::Failure(e) => nom::Err::Failure(e.input.into_fragment()),
703                }
704            }),Err(nom::Err::Error("1234\n")));
705        }
706    
707        #[test]
708        fn interval_data_300() {
709            let interval_data = record::IntervalData {
710                interval_date: NaiveDate::from_ymd(2004, 2, 1),
711                interval_value: vec![1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111],
712                quality_method: "A".into(),
713                reason_code: None,
714                reason_description: None,
715                update_datetime: NaiveDate::from_ymd(2004, 2, 2).and_hms(12, 0, 25),
716                msats_load_datetime: Some(NaiveDate::from_ymd(2004, 2, 2).and_hms(14, 25, 16)),
717                interval_events: None,
718            };
719    
720            let raw = "300,20040201,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,1.111,A,,,20040202120025,20040202142516";
721    
722            let res = record::IntervalData::parse(48, raw.into());
723    
724            assert_eq!(res.map(|(i,v)|(i.into_fragment(),v)),Ok(("",interval_data)));
725        }
726    
727        #[test]
728        fn interval_event_400() {
729            let interval_event = record::IntervalEvent {
730                start_interval: "1".into(),
731                end_interval: "20".into(),
732                quality_method: "F14".into(),
733                reason_code: Some("76".into()),
734                reason_description: None,
735            };
736    
737            let raw = "400,1,20,F14,76,\n";
738            let res = record::IntervalEvent::parse(raw.into());
739            assert_eq!(res.map(|(i,v)|(i.into_fragment(),v)),Ok(("\n",interval_event)));
740
741            let interval_event = record::IntervalEvent {
742                start_interval: "25".into(),
743                end_interval: "48".into(),
744                quality_method: "S14".into(),
745                reason_code: Some("1".into()),
746                reason_description: None,
747            };
748    
749            let raw = "400,25,48,S14,1,\n";
750            let res = record::IntervalEvent::parse(raw.into());
751            assert_eq!(res.map(|(i,v)|(i.into_fragment(),v)),Ok(("\n",interval_event)));
752
753            let interval_event = record::IntervalEvent {
754                start_interval: "21".into(),
755                end_interval: "24".into(),
756                quality_method: "A".into(),
757                reason_code: None,
758                reason_description: None,
759            };
760    
761            let raw = "400,21,24,A,,\n";
762            let res = record::IntervalEvent::parse(raw.into());
763            assert_eq!(res.map(|(r,v)| (r.into_fragment(),v)),Ok(("\n",interval_event)));
764        }
765    
766        #[test]
767        fn b2b_details_500() {
768            let interval_event = record::B2BDetails {
769                trans_code: "S".into(),
770                ret_service_order: "RETNSRVCEORD1".into(),
771                read_datetime: NaiveDate::from_ymd(2003,12,20).and_hms(15,45,0),
772                index_read: "001123.5".into(),
773            };
774    
775            let raw = "500,S,RETNSRVCEORD1,20031220154500,001123.5\n";
776            let res = record::B2BDetails::parse(raw.into());
777            assert_eq!(res.map(|(r,v)| (r.into_fragment(),v)),Ok(("\n",interval_event)));
778        }
779    
780        #[test]
781        fn end_of_data_900() {
782            let end_of_data = record::EndOfData {};
783    
784            let raw = "900\n";
785            let res = record::EndOfData::parse(raw.into());
786            assert_eq!(res.map(|(r,v)| (r.into_fragment(),v)),Ok(("",end_of_data)));
787        }
788    }
789}