1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.files.ilrs;
18
19 import java.io.BufferedReader;
20 import java.io.IOException;
21 import java.util.Optional;
22 import java.util.regex.Pattern;
23 import java.util.stream.Stream;
24
25 import org.hipparchus.util.FastMath;
26 import org.orekit.annotation.DefaultDataContext;
27 import org.orekit.data.DataContext;
28 import org.orekit.data.DataSource;
29 import org.orekit.errors.OrekitException;
30 import org.orekit.errors.OrekitMessages;
31 import org.orekit.files.ilrs.CRD.AnglesMeasurement;
32 import org.orekit.files.ilrs.CRD.CRDDataBlock;
33 import org.orekit.files.ilrs.CRD.MeteorologicalMeasurement;
34 import org.orekit.files.ilrs.CRD.RangeMeasurement;
35 import org.orekit.files.ilrs.CRDConfiguration.DetectorConfiguration;
36 import org.orekit.files.ilrs.CRDConfiguration.LaserConfiguration;
37 import org.orekit.files.ilrs.CRDConfiguration.MeteorologicalConfiguration;
38 import org.orekit.files.ilrs.CRDConfiguration.SoftwareConfiguration;
39 import org.orekit.files.ilrs.CRDConfiguration.SystemConfiguration;
40 import org.orekit.files.ilrs.CRDConfiguration.TimingSystemConfiguration;
41 import org.orekit.files.ilrs.CRDConfiguration.TransponderConfiguration;
42 import org.orekit.time.AbsoluteDate;
43 import org.orekit.time.DateComponents;
44 import org.orekit.time.TimeComponents;
45 import org.orekit.time.TimeScale;
46 import org.orekit.utils.units.Unit;
47 import org.orekit.utils.units.UnitsConverter;
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public class CRDParser {
62
63
64 public static final String DEFAULT_CRD_SUPPORTED_NAMES = "^(?!0+$)\\w{1,12}\\_\\d{6,8}.\\w{3}$";
65
66
67 private static final Unit NM = Unit.parse("nm");
68
69
70 private static final Unit KHZ = Unit.parse("kHz");
71
72
73 private static final Unit US = Unit.parse("µs");
74
75
76 private static final UnitsConverter MBAR_TO_BAR = new UnitsConverter(Unit.parse("mbar"), Unit.parse("bar"));
77
78
79 private static final String FILE_FORMAT = "CRD";
80
81
82 private static final Pattern SEPARATOR = Pattern.compile("\\s+");
83
84
85 private static final Pattern COMMA = Pattern.compile(",");
86
87
88 private final TimeScale timeScale;
89
90
91
92
93
94
95 @DefaultDataContext
96 public CRDParser() {
97 this(DataContext.getDefault().getTimeScales().getUTC());
98 }
99
100
101
102
103
104 public CRDParser(final TimeScale utc) {
105 this.timeScale = utc;
106 }
107
108
109
110
111
112 public TimeScale getTimeScale() {
113 return timeScale;
114 }
115
116
117
118
119
120
121
122 public CRD parse(final DataSource source) throws IOException {
123
124
125 final ParseInfo pi = new ParseInfo();
126
127 int lineNumber = 0;
128 Stream<LineParser> cdrParsers = Stream.of(LineParser.H1);
129 try (BufferedReader reader = new BufferedReader(source.getOpener().openReaderOnce())) {
130 for (String line = reader.readLine(); line != null; line = reader.readLine()) {
131 ++lineNumber;
132 final String l = line;
133 final Optional<LineParser> selected = cdrParsers.filter(p -> p.canHandle(l)).findFirst();
134 if (selected.isPresent()) {
135 try {
136 selected.get().parse(line, pi);
137 } catch (StringIndexOutOfBoundsException | NumberFormatException e) {
138 throw new OrekitException(e,
139 OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
140 lineNumber, source.getName(), line);
141 }
142 cdrParsers = selected.get().allowedNext();
143 }
144 if (pi.done) {
145
146 return pi.file;
147 }
148 }
149 }
150
151
152 throw new OrekitException(OrekitMessages.CRD_UNEXPECTED_END_OF_FILE, lineNumber);
153
154 }
155
156
157
158
159
160
161 private class ParseInfo {
162
163
164 private CRD file;
165
166
167 private int version;
168
169
170 private CRDDataBlock dataBlock;
171
172
173 private CRDHeader header;
174
175
176 private CRDConfiguration configurationRecords;
177
178
179 private TimeScale timeScale;
180
181
182 private DateComponents startEpoch;
183
184
185 private boolean done;
186
187
188
189
190 protected ParseInfo() {
191
192
193 this.done = false;
194 this.version = 1;
195 this.startEpoch = DateComponents.J2000_EPOCH;
196
197
198 this.file = new CRD();
199 this.header = new CRDHeader();
200 this.configurationRecords = new CRDConfiguration();
201 this.dataBlock = new CRDDataBlock();
202
203
204 this.timeScale = CRDParser.this.timeScale;
205
206 }
207
208 }
209
210
211 private enum LineParser {
212
213
214 H1("H1", "h1") {
215
216
217 @Override
218 public void parse(final String line, final ParseInfo pi) {
219
220
221 final String[] values = SEPARATOR.split(line);
222
223
224 final String format = values[1];
225 pi.version = Integer.parseInt(values[2]);
226
227
228 if (!format.equalsIgnoreCase(FILE_FORMAT)) {
229 throw new OrekitException(OrekitMessages.UNEXPECTED_FORMAT_FOR_ILRS_FILE, FILE_FORMAT, format);
230 }
231
232
233 pi.header.setFormat(format);
234 pi.header.setVersion(pi.version);
235
236
237 final int year = Integer.parseInt(values[3]);
238 final int month = Integer.parseInt(values[4]);
239 final int day = Integer.parseInt(values[5]);
240 pi.header.setProductionEpoch(new DateComponents(year, month, day));
241
242
243 pi.header.setProductionHour(Integer.parseInt(values[6]));
244
245 }
246
247
248 @Override
249 public Stream<LineParser> allowedNext() {
250 return Stream.of(H2, COMMENTS);
251 }
252
253 },
254
255
256 H2("H2", "h2") {
257
258
259 @Override
260 public void parse(final String line, final ParseInfo pi) {
261
262
263 final String[] values = SEPARATOR.split(line);
264
265
266 pi.header.setStationName(values[1]);
267
268
269 pi.header.setSystemIdentifier(Integer.parseInt(values[2]));
270 pi.header.setSystemNumber(Integer.parseInt(values[3]));
271 pi.header.setSystemOccupancy(Integer.parseInt(values[4]));
272
273
274 pi.header.setEpochIdentifier(Integer.parseInt(values[5]));
275
276
277 if (pi.version == 2) {
278 pi.header.setStationNetword(values[6]);
279 }
280
281 }
282
283
284 @Override
285 public Stream<LineParser> allowedNext() {
286 return Stream.of(H3, COMMENTS);
287 }
288
289 },
290
291
292 H3("H3", "h3") {
293
294
295 @Override
296 public void parse(final String line, final ParseInfo pi) {
297
298
299 final String[] values = SEPARATOR.split(line);
300
301
302 pi.header.setName(values[1]);
303
304
305 pi.header.setIlrsSatelliteId(values[2]);
306 pi.header.setSic(values[3]);
307 pi.header.setNoradId(values[4]);
308
309
310 pi.header.setSpacecraftEpochTimeScale(Integer.parseInt(values[5]));
311
312
313 pi.header.setTargetClass(Integer.parseInt(values[6]));
314 if (pi.version == 2) {
315 pi.header.setTargetLocation(Integer.parseInt(values[7]));
316 }
317
318 }
319
320
321 @Override
322 public Stream<LineParser> allowedNext() {
323 return Stream.of(H4, COMMENTS);
324 }
325
326 },
327
328
329 H4("H4", "h4") {
330
331
332 @Override
333 public void parse(final String line, final ParseInfo pi) {
334
335
336 final String[] values = SEPARATOR.split(line);
337
338
339 pi.header.setDataType(Integer.parseInt(values[1]));
340
341
342 final int yearS = Integer.parseInt(values[2]);
343 final int monthS = Integer.parseInt(values[3]);
344 final int dayS = Integer.parseInt(values[4]);
345 final int hourS = Integer.parseInt(values[5]);
346 final int minuteS = Integer.parseInt(values[6]);
347 final double secondS = Integer.parseInt(values[7]);
348
349 pi.startEpoch = new DateComponents(yearS, monthS, dayS);
350
351 pi.header.setStartEpoch(new AbsoluteDate(yearS, monthS, dayS,
352 hourS, minuteS, secondS,
353 pi.timeScale));
354
355
356 final int yearE = Integer.parseInt(values[8]);
357 final int monthE = Integer.parseInt(values[9]);
358 final int dayE = Integer.parseInt(values[10]);
359 final int hourE = Integer.parseInt(values[11]);
360 final int minuteE = Integer.parseInt(values[12]);
361 final double secondE = Integer.parseInt(values[13]);
362
363 pi.header.setEndEpoch(new AbsoluteDate(yearE, monthE, dayE,
364 hourE, minuteE, secondE,
365 pi.timeScale));
366
367
368 pi.header.setDataReleaseFlag(Integer.parseInt(values[14]));
369
370
371 pi.header.setIsTroposphericRefractionApplied(readBoolean(values[15]));
372 pi.header.setIsCenterOfMassCorrectionApplied(readBoolean(values[16]));
373 pi.header.setIsReceiveAmplitudeCorrectionApplied(readBoolean(values[17]));
374 pi.header.setIsStationSystemDelayApplied(readBoolean(values[18]));
375 pi.header.setIsTransponderDelayApplied(readBoolean(values[19]));
376
377
378 pi.header.setRangeType(Integer.parseInt(values[20]));
379
380
381 pi.header.setQualityIndicator(Integer.parseInt(values[21]));
382
383 }
384
385
386 @Override
387 public Stream<LineParser> allowedNext() {
388 return Stream.of(H5, C0, COMMENTS);
389 }
390
391 },
392
393
394 H5("H5", "h5") {
395
396
397 @Override
398 public void parse(final String line, final ParseInfo pi) {
399
400
401 final String[] values = SEPARATOR.split(line);
402
403
404 pi.header.setPredictionType(Integer.parseInt(values[1]));
405 pi.header.setYearOfCentury(Integer.parseInt(values[2]));
406 pi.header.setDateAndTime(values[3]);
407 pi.header.setPredictionProvider(values[4]);
408 pi.header.setSequenceNumber(Integer.parseInt(values[5]));
409
410 }
411
412
413 @Override
414 public Stream<LineParser> allowedNext() {
415 return Stream.of(C0, COMMENTS);
416 }
417
418 },
419
420
421 C0("C0", "c0") {
422
423
424 @Override
425 public void parse(final String line, final ParseInfo pi) {
426
427
428 final SystemConfiguration systemRecord = new SystemConfiguration();
429
430
431 final String[] values = SEPARATOR.split(line);
432
433
434 systemRecord.setWavelength(NM.toSI(Double.parseDouble(values[2])));
435
436
437 systemRecord.setSystemId(values[3]);
438
439
440 pi.configurationRecords.setSystemRecord(systemRecord);
441
442 }
443
444
445 @Override
446 public Stream<LineParser> allowedNext() {
447 return Stream.of(C1, C2, C3, C4, C5, C6, C7, TEN, ELEVEN, METEO, ANGLES, CALIB, STAT, COMPATIBILITY, COMMENTS);
448 }
449
450 },
451
452
453
454 C1("C1", "c1") {
455
456
457 @Override
458 public void parse(final String line, final ParseInfo pi) {
459
460
461 final LaserConfiguration laserRecord = new LaserConfiguration();
462
463
464 final String[] values = SEPARATOR.split(line);
465
466
467 laserRecord.setLaserId(values[2]);
468 laserRecord.setLaserType(values[3]);
469 laserRecord.setPrimaryWavelength(NM.toSI(Double.parseDouble(values[4])));
470 laserRecord.setNominalFireRate(Double.parseDouble(values[5]));
471 laserRecord.setPulseEnergy(Double.parseDouble(values[6]));
472 laserRecord.setPulseWidth(Double.parseDouble(values[7]));
473 laserRecord.setBeamDivergence(Double.parseDouble(values[8]));
474 laserRecord.setPulseInOutgoingSemiTrain(Integer.parseInt(values[9]));
475
476
477 pi.configurationRecords.setLaserRecord(laserRecord);
478
479 }
480
481
482 @Override
483 public Stream<LineParser> allowedNext() {
484 return Stream.of(C2, C3, C4, C5, C6, C7, TEN, ELEVEN, METEO, ANGLES, CALIB, STAT, COMPATIBILITY, COMMENTS);
485 }
486
487 },
488
489
490 C2("C2", "c2") {
491
492
493 @Override
494 public void parse(final String line, final ParseInfo pi) {
495
496
497 final DetectorConfiguration detectorRecord = new DetectorConfiguration();
498
499
500 final String[] values = SEPARATOR.split(line);
501
502
503 detectorRecord.setDetectorId(values[2]);
504 detectorRecord.setDetectorType(values[3]);
505 detectorRecord.setApplicableWavelength(NM.toSI(Double.parseDouble(values[4])));
506 detectorRecord.setQuantumEfficiency(Double.parseDouble(values[5]));
507 detectorRecord.setAppliedVoltage(Double.parseDouble(values[6]));
508 detectorRecord.setDarkCount(KHZ.toSI(Double.parseDouble(values[7])));
509 detectorRecord.setOutputPulseType(values[8]);
510 detectorRecord.setOutputPulseWidth(Double.parseDouble(values[9]));
511 detectorRecord.setSpectralFilter(NM.toSI(Double.parseDouble(values[10])));
512 detectorRecord.setTransmissionOfSpectralFilter(Double.parseDouble(values[11]));
513 detectorRecord.setSpatialFilter(Double.parseDouble(values[12]));
514 detectorRecord.setExternalSignalProcessing(values[13]);
515
516
517 if (pi.version == 2) {
518 detectorRecord.setAmplifierGain(Double.parseDouble(values[14]));
519 detectorRecord.setAmplifierBandwidth(KHZ.toSI(Double.parseDouble(values[15])));
520 detectorRecord.setAmplifierInUse(values[16]);
521 }
522
523
524 pi.configurationRecords.setDetectorRecord(detectorRecord);
525
526 }
527
528
529 @Override
530 public Stream<LineParser> allowedNext() {
531 return Stream.of(C3, C4, C5, C6, C7, TEN, ELEVEN, METEO, ANGLES, CALIB, STAT, COMPATIBILITY, COMMENTS);
532 }
533
534 },
535
536
537 C3("C3", "c3") {
538
539
540 @Override
541 public void parse(final String line, final ParseInfo pi) {
542
543
544 final TimingSystemConfiguration timingRecord = new TimingSystemConfiguration();
545
546
547 final String[] values = SEPARATOR.split(line);
548
549
550 timingRecord.setLocalTimingId(values[2]);
551 timingRecord.setTimeSource(values[3]);
552 timingRecord.setFrequencySource(values[4]);
553 timingRecord.setTimer(values[5]);
554 timingRecord.setTimerSerialNumber(values[6]);
555 timingRecord.setEpochDelayCorrection(US.toSI(Double.parseDouble(values[7])));
556
557
558 pi.configurationRecords.setTimingRecord(timingRecord);
559
560 }
561
562
563 @Override
564 public Stream<LineParser> allowedNext() {
565 return Stream.of(C4, C5, C6, C7, TEN, ELEVEN, METEO, ANGLES, CALIB, STAT, COMPATIBILITY, COMMENTS);
566 }
567
568 },
569
570
571 C4("C4", "c4") {
572
573
574 @Override
575 public void parse(final String line, final ParseInfo pi) {
576
577
578 final TransponderConfiguration transponderRecord = new TransponderConfiguration();
579
580
581 final String[] values = SEPARATOR.split(line);
582
583
584 transponderRecord.setTransponderId(values[2]);
585 transponderRecord.setStationUTCOffset(NM.toSI(Double.parseDouble(values[3])));
586 transponderRecord.setStationOscDrift(Double.parseDouble(values[4]));
587 transponderRecord.setTranspUTCOffset(NM.toSI(Double.parseDouble(values[5])));
588 transponderRecord.setTranspOscDrift(Double.parseDouble(values[6]));
589
590
591 transponderRecord.setTranspClkRefTime(Double.parseDouble(values[7]));
592
593
594 transponderRecord.setStationClockAndDriftApplied(Integer.parseInt(values[8]));
595 transponderRecord.setSpacecraftClockAndDriftApplied(Integer.parseInt(values[9]));
596
597
598 transponderRecord.setIsSpacecraftTimeSimplified(readBoolean(values[10]));
599
600
601 pi.configurationRecords.setTransponderRecord(transponderRecord);
602
603 }
604
605
606 @Override
607 public Stream<LineParser> allowedNext() {
608 return Stream.of(C5, C6, C7, TEN, ELEVEN, METEO, ANGLES, CALIB, STAT, COMPATIBILITY, COMMENTS);
609 }
610
611 },
612
613
614 C5("C5", "c5") {
615
616
617 @Override
618 public void parse(final String line, final ParseInfo pi) {
619
620
621 final SoftwareConfiguration softwareRecord = new SoftwareConfiguration();
622
623
624 final String[] values = SEPARATOR.split(line);
625
626
627 softwareRecord.setSoftwareId(values[2]);
628 softwareRecord.setTrackingSoftwares(COMMA.split(values[3]));
629 softwareRecord.setTrackingSoftwareVersions(COMMA.split(values[4]));
630 softwareRecord.setProcessingSoftwares(COMMA.split(values[5]));
631 softwareRecord.setProcessingSoftwareVersions(COMMA.split(values[6]));
632
633
634 pi.configurationRecords.setSoftwareRecord(softwareRecord);
635
636 }
637
638
639 @Override
640 public Stream<LineParser> allowedNext() {
641 return Stream.of(C6, C7, TEN, ELEVEN, METEO, ANGLES, CALIB, STAT, COMPATIBILITY, COMMENTS);
642 }
643
644 },
645
646
647 C6("C6", "c6") {
648
649
650 @Override
651 public void parse(final String line, final ParseInfo pi) {
652
653
654 final MeteorologicalConfiguration meteoRecord = new MeteorologicalConfiguration();
655
656
657 final String[] values = SEPARATOR.split(line);
658
659
660 meteoRecord.setMeteorologicalId(values[2]);
661 meteoRecord.setPressSensorManufacturer(values[3]);
662 meteoRecord.setPressSensorModel(values[4]);
663 meteoRecord.setPressSensorSerialNumber(values[5]);
664 meteoRecord.setTempSensorManufacturer(values[6]);
665 meteoRecord.setTempSensorModel(values[7]);
666 meteoRecord.setTempSensorSerialNumber(values[8]);
667 meteoRecord.setHumiSensorManufacturer(values[9]);
668 meteoRecord.setHumiSensorModel(values[10]);
669 meteoRecord.setHumiSensorSerialNumber(values[11]);
670
671
672 pi.configurationRecords.setMeteorologicalRecord(meteoRecord);
673
674 }
675
676
677 @Override
678 public Stream<LineParser> allowedNext() {
679 return Stream.of(C7, TEN, ELEVEN, METEO, ANGLES, CALIB, STAT, COMPATIBILITY, COMMENTS);
680 }
681
682 },
683
684
685 C7("C7", "c7") {
686
687
688 @Override
689 public void parse(final String line, final ParseInfo pi) {
690
691 }
692
693
694 @Override
695 public Stream<LineParser> allowedNext() {
696 return Stream.of(TEN, ELEVEN, METEO, ANGLES, CALIB, STAT, COMPATIBILITY, COMMENTS);
697 }
698
699 },
700
701
702 TEN("10") {
703
704
705 @Override
706 public void parse(final String line, final ParseInfo pi) {
707
708
709 final String[] values = SEPARATOR.split(line);
710
711
712 final double secOfDay = Double.parseDouble(values[1]);
713 final double timeOfFlight = Double.parseDouble(values[2]);
714 final int epochEvent = Integer.parseInt(values[4]);
715
716
717 final AbsoluteDate epoch = new AbsoluteDate(pi.startEpoch, new TimeComponents(secOfDay), pi.timeScale);
718 final RangeMeasurement range = new RangeMeasurement(epoch, timeOfFlight, epochEvent);
719 pi.dataBlock.addRangeData(range);
720
721 }
722
723
724 @Override
725 public Stream<LineParser> allowedNext() {
726 return Stream.of(H8, TEN, TWELVE, METEO, ANGLES, CALIB, STAT, COMPATIBILITY, COMMENTS);
727 }
728
729 },
730
731
732 ELEVEN("11") {
733
734
735 @Override
736 public void parse(final String line, final ParseInfo pi) {
737
738
739 final String[] values = SEPARATOR.split(line);
740
741
742 final double secOfDay = Double.parseDouble(values[1]);
743 final double timeOfFlight = Double.parseDouble(values[2]);
744 final int epochEvent = Integer.parseInt(values[4]);
745 final double snr = (pi.version == 2) ? Double.parseDouble(values[13]) : Double.NaN;
746
747
748 final AbsoluteDate epoch = new AbsoluteDate(pi.startEpoch, new TimeComponents(secOfDay), pi.timeScale);
749 final RangeMeasurement range = new RangeMeasurement(epoch, timeOfFlight, epochEvent, snr);
750 pi.dataBlock.addRangeData(range);
751
752 }
753
754
755 @Override
756 public Stream<LineParser> allowedNext() {
757 return Stream.of(H8, ELEVEN, TWELVE, METEO, ANGLES, CALIB, STAT, COMPATIBILITY, COMMENTS);
758 }
759
760 },
761
762
763 TWELVE("12") {
764
765
766 @Override
767 public void parse(final String line, final ParseInfo pi) {
768
769 }
770
771
772 @Override
773 public Stream<LineParser> allowedNext() {
774 return Stream.of(H8, TEN, ELEVEN, TWELVE, METEO, ANGLES, CALIB, STAT, COMPATIBILITY, COMMENTS);
775 }
776
777 },
778
779
780 METEO("20") {
781
782
783 @Override
784 public void parse(final String line, final ParseInfo pi) {
785
786
787 final String[] values = SEPARATOR.split(line);
788
789
790 final double secOfDay = Double.parseDouble(values[1]);
791 final double pressure = MBAR_TO_BAR.convert(Double.parseDouble(values[2]));
792 final double temperature = Double.parseDouble(values[3]);
793 final double humidity = Double.parseDouble(values[4]);
794
795
796 final AbsoluteDate epoch = new AbsoluteDate(pi.startEpoch, new TimeComponents(secOfDay), pi.timeScale);
797 final MeteorologicalMeasurement meteo = new MeteorologicalMeasurement(epoch, pressure,
798 temperature, humidity);
799 pi.dataBlock.addMeteoData(meteo);
800
801 }
802
803
804 @Override
805 public Stream<LineParser> allowedNext() {
806 return Stream.of(H8, METEO, METEO_SUPP, TEN, ELEVEN, TWELVE, ANGLES, CALIB, STAT, COMPATIBILITY, COMMENTS);
807 }
808
809 },
810
811
812 METEO_SUPP("21") {
813
814
815 @Override
816 public void parse(final String line, final ParseInfo pi) {
817
818 }
819
820
821 @Override
822 public Stream<LineParser> allowedNext() {
823 return Stream.of(H8, METEO, METEO_SUPP, TEN, ELEVEN, TWELVE, ANGLES, CALIB, STAT, COMPATIBILITY, COMMENTS);
824 }
825
826 },
827
828
829 ANGLES("30") {
830
831
832 @Override
833 public void parse(final String line, final ParseInfo pi) {
834
835
836 final String[] values = SEPARATOR.split(line);
837
838
839 final double secOfDay = Double.parseDouble(values[1]);
840 final double azmiuth = FastMath.toRadians(Double.parseDouble(values[2]));
841 final double elevation = FastMath.toRadians(Double.parseDouble(values[3]));
842 final int directionFlag = Integer.parseInt(values[4]);
843 final int orginFlag = Integer.parseInt(values[5]);
844 final boolean isRefractionCorrected = readBoolean(values[6]);
845
846
847
848 double azimuthRate = Double.NaN;
849 double elevationRate = Double.NaN;
850 if (pi.version == 2) {
851 azimuthRate = readDoubleWithNaN(values[7]);
852 elevationRate = readDoubleWithNaN(values[8]);
853 }
854
855
856 final AbsoluteDate epoch = new AbsoluteDate(pi.startEpoch, new TimeComponents(secOfDay), pi.timeScale);
857 final AnglesMeasurement angles = new AnglesMeasurement(epoch, azmiuth, elevation,
858 directionFlag, orginFlag,
859 isRefractionCorrected,
860 azimuthRate, elevationRate);
861 pi.dataBlock.addAnglesData(angles);
862
863 }
864
865
866 @Override
867 public Stream<LineParser> allowedNext() {
868 return Stream.of(H8, METEO, TEN, ELEVEN, ANGLES, CALIB, STAT, COMPATIBILITY, COMMENTS);
869 }
870
871 },
872
873
874 CALIB("40") {
875
876
877 @Override
878 public void parse(final String line, final ParseInfo pi) {
879
880 }
881
882
883 @Override
884 public Stream<LineParser> allowedNext() {
885 return Stream.of(H8, METEO, CALIB, CALIB_DETAILS, CALIB_SHOT, TEN, ELEVEN, TWELVE, ANGLES, STAT, COMPATIBILITY, COMMENTS);
886 }
887
888 },
889
890
891 CALIB_DETAILS("41") {
892
893
894 @Override
895 public void parse(final String line, final ParseInfo pi) {
896
897 }
898
899
900 @Override
901 public Stream<LineParser> allowedNext() {
902 return Stream.of(H8, METEO, CALIB, CALIB_DETAILS, CALIB_SHOT, TEN, ELEVEN, TWELVE, ANGLES, STAT, COMPATIBILITY, COMMENTS);
903 }
904
905 },
906
907
908 CALIB_SHOT("42") {
909
910
911 @Override
912 public void parse(final String line, final ParseInfo pi) {
913
914 }
915
916
917 @Override
918 public Stream<LineParser> allowedNext() {
919 return Stream.of(H8, METEO, CALIB, CALIB_DETAILS, CALIB_SHOT, TEN, ELEVEN, TWELVE, ANGLES, STAT, COMPATIBILITY, COMMENTS);
920 }
921
922 },
923
924
925 STAT("50") {
926
927
928 @Override
929 public void parse(final String line, final ParseInfo pi) {
930
931 }
932
933
934 @Override
935 public Stream<LineParser> allowedNext() {
936 return Stream.of(H8, METEO, CALIB, CALIB_DETAILS, CALIB_SHOT, TEN, ELEVEN, TWELVE, ANGLES, STAT, COMPATIBILITY, H8, COMMENTS);
937 }
938
939 },
940
941
942 COMPATIBILITY("60") {
943
944
945 @Override
946 public void parse(final String line, final ParseInfo pi) {
947
948 }
949
950
951 @Override
952 public Stream<LineParser> allowedNext() {
953 return Stream.of(H8, METEO, CALIB, CALIB_DETAILS, CALIB_SHOT, TEN, ELEVEN, TWELVE, ANGLES, STAT, COMPATIBILITY, COMMENTS);
954 }
955
956 },
957
958
959 COMMENTS("00") {
960
961
962 @Override
963 public void parse(final String line, final ParseInfo pi) {
964
965
966 final String comment = line.split(getFirstIdentifier())[1].trim();
967 pi.file.getComments().add(comment);
968
969 }
970
971
972 @Override
973 public Stream<LineParser> allowedNext() {
974 return Stream.of(H1, H2, H3, H4, H5, H8, H9, C0, C1, C2, C3, C4, C5, C6, C7, TEN, ELEVEN, TWELVE, METEO,
975 METEO_SUPP, ANGLES, CALIB, CALIB_DETAILS, CALIB_SHOT, STAT, COMPATIBILITY, COMMENTS);
976
977 }
978
979 },
980
981
982 H8("H8", "h8") {
983
984
985 @Override
986 public void parse(final String line, final ParseInfo pi) {
987
988
989 pi.dataBlock.setHeader(pi.header);
990 pi.dataBlock.setConfigurationRecords(pi.configurationRecords);
991
992
993 pi.file.addDataBlock(pi.dataBlock);
994
995
996 pi.startEpoch = DateComponents.J2000_EPOCH;
997 pi.header = new CRDHeader();
998 pi.configurationRecords = new CRDConfiguration();
999 pi.dataBlock = new CRDDataBlock();
1000
1001 }
1002
1003
1004 @Override
1005 public Stream<LineParser> allowedNext() {
1006 return Stream.of(H1, H9, COMMENTS);
1007 }
1008
1009 },
1010
1011
1012 H9("H9", "h9") {
1013
1014
1015 @Override
1016 public void parse(final String line, final ParseInfo pi) {
1017 pi.done = true;
1018 }
1019
1020
1021 @Override
1022 public Stream<LineParser> allowedNext() {
1023 return Stream.of(H9);
1024 }
1025
1026 };
1027
1028
1029 private final Pattern[] patterns;
1030
1031
1032 private final String[] identifiers;
1033
1034
1035
1036
1037 LineParser(final String... identifier) {
1038 this.identifiers = identifier;
1039
1040 this.patterns = new Pattern[identifiers.length];
1041 for (int index = 0; index < patterns.length; index++) {
1042 patterns[index] = Pattern.compile(identifiers[index]);
1043 }
1044 }
1045
1046
1047
1048
1049
1050 public String getFirstIdentifier() {
1051 return identifiers[0];
1052 }
1053
1054
1055
1056
1057
1058 public abstract void parse(String line, ParseInfo pi);
1059
1060
1061
1062
1063 public abstract Stream<LineParser> allowedNext();
1064
1065
1066
1067
1068
1069 public boolean canHandle(final String line) {
1070
1071 final String lineId = SEPARATOR.split(line)[0];
1072
1073 for (Pattern pattern : patterns) {
1074 if (pattern.matcher(lineId).matches()) {
1075 return true;
1076 }
1077 }
1078
1079 return false;
1080 }
1081
1082
1083
1084
1085
1086
1087 private static boolean readBoolean(final String value) {
1088 return Integer.parseInt(value) == 1;
1089 }
1090
1091
1092
1093
1094
1095
1096 private static double readDoubleWithNaN(final String value) {
1097 return "na".equals(value) ? Double.NaN : Double.parseDouble(value);
1098 }
1099
1100 }
1101
1102 }