1   /* Copyright 2002-2021 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.files.ccsds.utils.lexical;
18  
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.List;
22  import java.util.Locale;
23  import java.util.regex.Pattern;
24  import java.util.stream.Collectors;
25  import java.util.stream.Stream;
26  
27  import org.hipparchus.geometry.euclidean.threed.Vector3D;
28  import org.orekit.bodies.CelestialBodies;
29  import org.orekit.bodies.CelestialBody;
30  import org.orekit.errors.OrekitException;
31  import org.orekit.errors.OrekitMessages;
32  import org.orekit.files.ccsds.definitions.BodyFacade;
33  import org.orekit.files.ccsds.definitions.CelestialBodyFrame;
34  import org.orekit.files.ccsds.definitions.CenterName;
35  import org.orekit.files.ccsds.definitions.FrameFacade;
36  import org.orekit.files.ccsds.definitions.OrbitRelativeFrame;
37  import org.orekit.files.ccsds.definitions.SpacecraftBodyFrame;
38  import org.orekit.files.ccsds.definitions.TimeSystem;
39  import org.orekit.files.ccsds.ndm.ParsedUnitsBehavior;
40  import org.orekit.files.ccsds.utils.ContextBinding;
41  import org.orekit.time.AbsoluteDate;
42  import org.orekit.utils.units.Unit;
43  
44  /** Token occurring during CCSDS file parsing.
45   * <p>
46   * Parse tokens correspond to:
47   * <ul>
48   *   <li>bloc or entry start</li>
49   *   <li>entry content</li>
50   *   <li>bloc or entry end</li>
51   *   <li>raw lines</li>
52   * </ul>
53   * @see MessageParser
54   * @author Luc Maisonobe
55   * @since 11.0
56   */
57  public class ParseToken {
58  
59      /** Pattern for dash. */
60      private static final Pattern DASH = Pattern.compile("-");
61  
62      /** Pattern for spaces. */
63      private static final Pattern SPACE = Pattern.compile("\\p{Space}+");
64  
65      /** Pattern for splitting comma-separated lists. */
66      private static final Pattern SPLIT_AT_COMMAS = Pattern.compile("\\p{Space}*,\\p{Space}*");
67  
68      /** Pattern for true boolean value. */
69      private static final Pattern BOOLEAN_TRUE = Pattern.compile("(?:yes)|(?:true)",
70                                                                  Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
71  
72      /** Pattern for false boolean value. */
73      private static final Pattern BOOLEAN_FALSE = Pattern.compile("(?:no)|(?:false)",
74                                                                   Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
75  
76      /** Type of the token. */
77      private TokenType type;
78  
79      /** Name of the entry. */
80      private final String name;
81  
82      /** Entry content. */
83      private final String content;
84  
85      /** Units of the entry. */
86      private final Unit units;
87  
88      /** Number of the line from which pair is extracted. */
89      private final int lineNumber;
90  
91      /** Name of the file. */
92      private final String fileName;
93  
94      /** Simple constructor.
95       * @param type type of the token
96       * @param name name of the block or entry
97       * @param content entry content
98       * @param units units of the entry
99       * @param lineNumber number of the line in the CCSDS data message
100      * @param fileName name of the file
101      */
102     public ParseToken(final TokenType type, final String name, final String content, final Unit units,
103                       final int lineNumber, final String fileName) {
104         this.type       = type;
105         this.name       = name;
106         this.content    = content;
107         this.units      = units;
108         this.lineNumber = lineNumber;
109         this.fileName   = fileName;
110     }
111 
112     /** Get the type of the token.
113      * @return type of the token
114      */
115     public TokenType getType() {
116         return type;
117     }
118 
119     /** Get the name of the block or entry.
120      * @return name of the block or entry
121      */
122     public String getName() {
123         return name;
124     }
125 
126     /** Get the raw content of the entry.
127      * @return entry raw content
128      */
129     public String getRawContent() {
130         return content;
131     }
132 
133     /** Get the content of the entry.
134      * <p>
135      * Free-text strings are normalized by replacing all occurrences
136      * of '_' with space, and collapsing several spaces as one space only.
137      * </p>
138      * @return entry content
139      */
140     public String getContentAsNormalizedString() {
141         return SPACE.matcher(content.replace('_', ' ')).replaceAll(" ").trim();
142     }
143 
144     /** Get the content of the entry as a list of free-text strings.
145      * <p>
146      * Free-text strings are normalized by replacing all occurrences
147      * of '_' with space, and collapsing several spaces as one space only.
148      * </p>
149      * @return content of the entry as a list of free-test strings
150      */
151     public List<String> getContentAsNormalizedList() {
152         return Arrays.asList(SPLIT_AT_COMMAS.split(getContentAsNormalizedString()));
153     }
154 
155     /** Get the content of the entry as normalized and uppercased.
156      * @return entry normalized and uppercased content
157      */
158     public String getContentAsUppercaseString() {
159         return getContentAsNormalizedString().toUpperCase(Locale.US);
160     }
161 
162     /** Get the content of the entry as a list of normalized and uppercased strings.
163      * @return content of the entry as a list of normalized and uppercased strings
164      */
165     public List<String> getContentAsUppercaseList() {
166         return Arrays.asList(SPLIT_AT_COMMAS.split(getContentAsUppercaseString()));
167     }
168 
169     /** Get the content of the entry as an enum.
170      * @param cls enum class
171      * @param <T> type of the enum
172      * @return entry content
173      */
174     public <T extends Enum<T>> T getContentAsEnum(final Class<T> cls) {
175         return toEnum(cls, getRawContent());
176     }
177 
178     /** Get the content of the entry as a list of enum.
179      * @param cls enum class
180      * @param <T> type of the enum
181      * @return entry content
182      */
183     public <T extends Enum<T>> List<T> getContentAsEnumList(final Class<T> cls) {
184         final String[] elements = SPLIT_AT_COMMAS.split(getRawContent());
185         final List<T> list = new ArrayList<>(elements.length);
186         for (int i = 0; i < elements.length; ++i) {
187             list.add(toEnum(cls, elements[i]));
188         }
189         return list;
190     }
191 
192     /** Get the content of the entry as a double.
193      * @return content as a double
194      */
195     public double getContentAsDouble() {
196         try {
197             return Double.parseDouble(content);
198         } catch (NumberFormatException nfe) {
199             throw generateException(nfe);
200         }
201     }
202 
203     /** Get the content of the entry as a vector.
204      * @return content as a vector
205      */
206     public Vector3D getContentAsVector() {
207         try {
208             final String[] fields = SPACE.split(content);
209             if (fields.length == 3) {
210                 return new Vector3D(Double.parseDouble(fields[0]),
211                                     Double.parseDouble(fields[1]),
212                                     Double.parseDouble(fields[2]));
213             }
214         } catch (NumberFormatException nfe) {
215             // ignored, error handled below, together with wrong number of fields
216         }
217         throw generateException(null);
218     }
219 
220     /** Get the content of the entry as a boolean.
221      * @return content as a boolean
222      */
223     public boolean getContentAsBoolean() {
224         if (BOOLEAN_TRUE.matcher(content).matches()) {
225             return true;
226         } else if (BOOLEAN_FALSE.matcher(content).matches()) {
227             return false;
228         } else {
229             throw generateException(null);
230         }
231     }
232 
233     /** Get the content of the entry as an integer.
234      * @return content as an integer
235      */
236     public int getContentAsInt() {
237         try {
238             return Integer.parseInt(content);
239         } catch (NumberFormatException nfe) {
240             throw generateException(nfe);
241         }
242     }
243 
244     /** Get the content of the entry as an uppercase character.
245      * @return content as an uppercase character
246      */
247     public char getContentAsUppercaseCharacter() {
248         try {
249             return getContentAsUppercaseString().charAt(0);
250         } catch (NumberFormatException nfe) {
251             throw generateException(nfe);
252         }
253     }
254 
255     /** Get the units.
256      * @return units of the entry (may be null)
257      */
258     public Unit getUnits() {
259         return units;
260     }
261 
262     /** Get the number of the line in the CCSDS data message.
263      * @return number of the line in the CCSDS data message
264      */
265     public int getLineNumber() {
266         return lineNumber;
267     }
268 
269     /** Get the name of the file.
270      * @return name of the file
271      */
272     public String getFileName() {
273         return fileName;
274     }
275 
276     /** Process the content as a normalized string.
277      * @param consumer consumer of the normalized string
278      * @return always returns {@code true}
279      * @see #processAsUppercaseString(StringConsumer)
280      */
281     public boolean processAsNormalizedString(final StringConsumer consumer) {
282         if (type == TokenType.ENTRY) {
283             consumer.accept(getContentAsNormalizedString());
284         }
285         return true;
286     }
287 
288     /** Process the content as a normalized uppercase string.
289      * @param consumer consumer of the normalized uppercase string
290      * @return always returns {@code true}
291      * @see #processAsNormalizedString(StringConsumer)
292      */
293     public boolean processAsUppercaseString(final StringConsumer consumer) {
294         if (type == TokenType.ENTRY) {
295             consumer.accept(getContentAsUppercaseString());
296         }
297         return true;
298     }
299 
300     /** Process the content as an indexed normalized string.
301      * @param index index
302      * @param consumer consumer of the indexed normalized string
303      * @return always returns {@code true}
304      */
305     public boolean processAsIndexedNormalizedString(final int index, final IndexedStringConsumer consumer) {
306         if (type == TokenType.ENTRY) {
307             consumer.accept(index, getContentAsNormalizedString());
308         }
309         return true;
310     }
311 
312     /** Process the content as an indexed normalized uppercase string.
313      * @param index index
314      * @param consumer consumer of the indexed normalized uppercase string
315      * @return always returns {@code true}
316      */
317     public boolean processAsIndexedUppercaseString(final int index, final IndexedStringConsumer consumer) {
318         if (type == TokenType.ENTRY) {
319             consumer.accept(index, getContentAsUppercaseString());
320         }
321         return true;
322     }
323 
324     /** Process the content as a list of normalized strings.
325      * @param consumer consumer of the normalized strings list
326      * @return always returns {@code true}
327      */
328     public boolean processAsNormalizedList(final StringListConsumer consumer) {
329         if (type == TokenType.ENTRY) {
330             consumer.accept(getContentAsNormalizedList());
331         }
332         return true;
333     }
334 
335     /** Process the content as a list of normalized uppercase strings.
336      * @param consumer consumer of the normalized uppercase strings list
337      * @return always returns {@code true}
338      */
339     public boolean processAsUppercaseList(final StringListConsumer consumer) {
340         if (type == TokenType.ENTRY) {
341             consumer.accept(getContentAsUppercaseList());
342         }
343         return true;
344     }
345 
346     /** Process the content as an enum.
347      * @param cls enum class
348      * @param consumer consumer of the enum
349      * @param <T> type of the enum
350      * @return always returns {@code true}
351      */
352     public <T extends Enum<T>> boolean processAsEnum(final Class<T> cls, final EnumConsumer<T> consumer) {
353         if (type == TokenType.ENTRY) {
354             consumer.accept(getContentAsEnum(cls));
355         }
356         return true;
357     }
358 
359     /** Process the content as a list of enums.
360      * @param cls enum class
361      * @param consumer consumer of the enums list
362      * @param <T> type of the enum
363      * @return always returns {@code true}
364      */
365     public <T extends Enum<T>> boolean processAsEnumsList(final Class<T> cls, final EnumListConsumer<T> consumer) {
366         if (type == TokenType.ENTRY) {
367             consumer.accept(getContentAsEnumList(cls));
368         }
369         return true;
370     }
371 
372     /** Process the content as a boolean.
373      * @param consumer consumer of the boolean
374      * @return always returns {@code true}
375      */
376     public boolean processAsBoolean(final BooleanConsumer consumer) {
377         if (type == TokenType.ENTRY) {
378             consumer.accept(getContentAsBoolean());
379         }
380         return true;
381     }
382 
383     /** Process the content as an integer.
384      * @param consumer consumer of the integer
385      * @return always returns {@code true}
386      */
387     public boolean processAsInteger(final IntConsumer consumer) {
388         if (type == TokenType.ENTRY) {
389             consumer.accept(getContentAsInt());
390         }
391         return true;
392     }
393 
394     /** Process the content as an array of integers.
395      * @param consumer consumer of the array
396      * @return always returns {@code true}
397      */
398     public boolean processAsIntegerArray(final IntegerArrayConsumer consumer) {
399         try {
400             if (type == TokenType.ENTRY) {
401                 final String[] fields = SPLIT_AT_COMMAS.split(getRawContent());
402                 final int[] integers = new int[fields.length];
403                 for (int i = 0; i < fields.length; ++i) {
404                     integers[i] = Integer.parseInt(fields[i]);
405                 }
406                 consumer.accept(integers);
407             }
408             return true;
409         } catch (NumberFormatException nfe) {
410             throw generateException(nfe);
411         }
412     }
413 
414     /** Process the content as a normalized character.
415      * @param consumer consumer of the normalized character
416      * @return always returns {@code true}
417      */
418     public boolean processAsNormalizedCharacter(final CharConsumer consumer) {
419         if (type == TokenType.ENTRY) {
420             consumer.accept(getContentAsUppercaseCharacter());
421         }
422         return true;
423     }
424 
425     /** Process the content as a double.
426      * @param standard units of parsed content as specified by CCSDS standard
427      * @param behavior behavior to adopt for parsed unit
428      * @param consumer consumer of the double
429      * @return always returns {@code true}
430      */
431     public boolean processAsDouble(final Unit standard, final ParsedUnitsBehavior behavior,
432                                    final DoubleConsumer consumer) {
433         if (type == TokenType.ENTRY) {
434             consumer.accept(behavior.select(getUnits(), standard).toSI(getContentAsDouble()));
435         }
436         return true;
437     }
438 
439     /** Process the content as an labeled double.
440      * @param label label
441      * @param standard units of parsed content as specified by CCSDS standard
442      * @param behavior behavior to adopt for parsed unit
443      * @param consumer consumer of the indexed double
444      * @return always returns {@code true}
445      */
446     public boolean processAsLabeledDouble(final char label,
447                                           final Unit standard, final ParsedUnitsBehavior behavior,
448                                           final LabeledDoubleConsumer consumer) {
449         if (type == TokenType.ENTRY) {
450             consumer.accept(label, behavior.select(getUnits(), standard).toSI(getContentAsDouble()));
451         }
452         return true;
453     }
454 
455     /** Process the content as an indexed double.
456      * @param i index
457      * @param standard units of parsed content as specified by CCSDS standard
458      * @param behavior behavior to adopt for parsed unit
459      * @param consumer consumer of the indexed double
460      * @return always returns {@code true}
461      */
462     public boolean processAsIndexedDouble(final int i,
463                                           final Unit standard, final ParsedUnitsBehavior behavior,
464                                           final IndexedDoubleConsumer consumer) {
465         if (type == TokenType.ENTRY) {
466             consumer.accept(i, behavior.select(getUnits(), standard).toSI(getContentAsDouble()));
467         }
468         return true;
469     }
470 
471     /** Process the content as a doubly-indexed double.
472      * @param i first index
473      * @param j second index
474      * @param standard units of parsed content as specified by CCSDS standard
475      * @param behavior behavior to adopt for parsed unit
476      * @param consumer consumer of the doubly-indexed double
477      * @return always returns {@code true}
478      */
479     public boolean processAsDoublyIndexedDouble(final int i, final int j,
480                                                 final Unit standard, final ParsedUnitsBehavior behavior,
481                                                 final DoublyIndexedDoubleConsumer consumer) {
482         if (type == TokenType.ENTRY) {
483             consumer.accept(i, j, behavior.select(getUnits(), standard).toSI(getContentAsDouble()));
484         }
485         return true;
486     }
487 
488     /** Process the content as a vector.
489      * @param consumer consumer of the vector
490      * @return always returns {@code true} (or throws an exception)
491      */
492     public boolean processAsVector(final VectorConsumer consumer) {
493         if (type == TokenType.ENTRY) {
494             consumer.accept(getContentAsVector());
495         }
496         return true;
497     }
498 
499     /** Process the content as a date.
500      * @param consumer consumer of the date
501      * @param context context binding
502      * @return always returns {@code true} (or throws an exception)
503      */
504     public boolean processAsDate(final DateConsumer consumer, final ContextBinding context) {
505         if (type == TokenType.ENTRY) {
506             if (context.getTimeSystem() == null) {
507                 throw new OrekitException(OrekitMessages.CCSDS_TIME_SYSTEM_NOT_READ_YET,
508                                           getLineNumber(), getFileName());
509             }
510             consumer.accept(context.getTimeSystem().getConverter(context).parse(content));
511         }
512         return true;
513     }
514 
515     /** Process the content as a time system.
516      * @param consumer consumer of the time system
517      * @return always returns {@code true} (or throws an exception)
518      */
519     public boolean processAsTimeSystem(final TimeSystemConsumer consumer) {
520         if (type == TokenType.ENTRY) {
521             consumer.accept(TimeSystem.parse(getContentAsUppercaseString()));
522         }
523         return true;
524     }
525 
526     /** Process the content as a frame.
527      * @param consumer consumer of the frame
528      * @param context context binding
529      * @param allowCelestial if true, {@link CelestialBodyFrame} are allowed
530      * @param allowOrbit if true, {@link OrbitRelativeFrame} are allowed
531      * @param allowSpacecraft if true, {@link SpacecraftBodyFrame} are allowed
532      * @return always returns {@code true}
533      */
534     public boolean processAsFrame(final FrameConsumer consumer, final ContextBinding context,
535                                   final boolean allowCelestial, final boolean allowOrbit,
536                                   final boolean allowSpacecraft) {
537         if (type == TokenType.ENTRY) {
538             try {
539                 consumer.accept(FrameFacade.parse(DASH.
540                                                   matcher(getContentAsUppercaseString()).
541                                                   replaceAll("").
542                                                   replace(' ', '_'),
543                                                   context.getConventions(),
544                                                   context.isSimpleEOP(), context.getDataContext(),
545                                                   allowCelestial, allowOrbit, allowSpacecraft));
546             } catch (OrekitException oe) {
547                 throw generateException(oe);
548             }
549         }
550         return true;
551     }
552 
553     /** Process the content as a body center.
554      * @param consumer consumer of the body center
555      * @param celestialBodies factory for celestial bodies
556      * @return always returns {@code true}
557      */
558     public boolean processAsCenter(final CenterConsumer consumer, final CelestialBodies celestialBodies) {
559         if (type == TokenType.ENTRY) {
560             final String centerName = getContentAsUppercaseString();
561             consumer.accept(new BodyFacade(centerName, body(centerName, celestialBodies)));
562         }
563         return true;
564     }
565 
566     /** Process the content as a body center list.
567      * @param consumer consumer of the body center list
568      * @param celestialBodies factory for celestial bodies
569      * @return always returns {@code true}
570      */
571     public boolean processAsCenterList(final CenterListConsumer consumer, final CelestialBodies celestialBodies) {
572         if (type == TokenType.ENTRY) {
573             final List<BodyFacade> facades = new ArrayList<>();
574             for (final String centerName : SPLIT_AT_COMMAS.split(getContentAsUppercaseString())) {
575                 facades.add(new BodyFacade(centerName, body(centerName, celestialBodies)));
576             }
577             consumer.accept(facades);
578         }
579         return true;
580     }
581 
582     /** Process the content as a list of units.
583      * @param consumer consumer of the time scale
584      * @return always returns {@code true} (or throws an exception)
585      */
586     public boolean processAsUnitList(final UnitListConsumer consumer) {
587         if (type == TokenType.ENTRY) {
588             final String bracketed = getContentAsNormalizedString();
589             if (bracketed.charAt(0) != '[' || bracketed.charAt(bracketed.length() - 1) != ']') {
590                 throw generateException(null);
591             }
592             final String unbracketed = bracketed.substring(1, bracketed.length() - 1).trim();
593             try {
594                 consumer.accept(Stream.of(SPLIT_AT_COMMAS.split(unbracketed)).
595                                 map(s -> Unit.parse(s)).
596                                 collect(Collectors.toList()));
597             } catch (OrekitException oe) {
598                 // one unit is unknown
599                 throw generateException(oe);
600             }
601         }
602         return true;
603     }
604 
605     /** Generate a parse exception for this entry.
606      * @param cause underlying cause exception (may be null)
607      * @return exception for this entry
608      */
609     public OrekitException generateException(final Exception cause) {
610         return new OrekitException(cause, OrekitMessages.UNABLE_TO_PARSE_ELEMENT_IN_FILE,
611                                    getName(), getLineNumber(), getFileName());
612     }
613 
614     /** Get the body corresponding to a center name.
615      * @param centerName name of the center
616      * @param celestialBodies factory for celestial bodies
617      * @return celestial body corresponding to name, or null
618      */
619     private CelestialBody body(final String centerName, final CelestialBodies celestialBodies) {
620 
621         // convert some known names
622         final String canonicalValue;
623         if (centerName.equals("SOLAR SYSTEM BARYCENTER") || centerName.equals("SSB")) {
624             canonicalValue = "SOLAR_SYSTEM_BARYCENTER";
625         } else if (centerName.equals("EARTH MOON BARYCENTER") || centerName.equals("EARTH-MOON BARYCENTER") ||
626                         centerName.equals("EARTH BARYCENTER") || centerName.equals("EMB")) {
627             canonicalValue = "EARTH_MOON";
628         } else {
629             canonicalValue = centerName;
630         }
631 
632         try {
633             return CenterName.valueOf(canonicalValue).getCelestialBody(celestialBodies);
634         } catch (IllegalArgumentException iae) {
635             // ignored, we just let body set to null
636             return null;
637         }
638 
639     }
640 
641     /** Convert a value to an enum.
642      * @param cls enum class
643      * @param value value to convert to an enum
644      * @param <T> type of the enum
645      * @return enumerate corresponding to the value
646      */
647     private <T extends Enum<T>> T toEnum(final Class<T> cls, final String value) {
648         // first replace space characters
649         final String noSpace = value.replace(' ', '_');
650         try {
651             // first try without changing case, as some CCSDS enums are mixed case (like RangeUnits for TDM)
652             return Enum.valueOf(cls, noSpace);
653         } catch (IllegalArgumentException iae1) {
654             try {
655                 // second try, using more standard uppercase
656                 return Enum.valueOf(cls, noSpace.toUpperCase(Locale.US));
657             } catch (IllegalArgumentException iae2) {
658                 // use the first exception for the message
659                 throw generateException(iae1);
660             }
661         }
662     }
663 
664     /** Interface representing instance methods that consume string values. */
665     public interface StringConsumer {
666         /** Consume a string.
667          * @param value value to consume
668          */
669         void accept(String value);
670     }
671 
672     /** Interface representing instance methods that consume indexed string values. */
673     public interface IndexedStringConsumer {
674         /** Consume an indexed string.
675          * @param index index
676          * @param value value to consume
677          */
678         void accept(int index, String value);
679     }
680 
681     /** Interface representing instance methods that consume lists of strings values. */
682     public interface StringListConsumer {
683         /** Consume a list of strings.
684          * @param value value to consume
685          */
686         void accept(List<String> value);
687     }
688 
689     /** Interface representing instance methods that consume enum values.
690      * @param <T> type of the enum
691      */
692     public interface EnumConsumer<T extends Enum<T>> {
693         /** Consume an enum.
694          * @param value value to consume
695          */
696         void accept(T value);
697     }
698 
699     /** Interface representing instance methods that consume lists of enum values.
700      * @param <T> type of the enum
701      */
702     public interface EnumListConsumer<T extends Enum<T>> {
703         /** Consume an enum.
704          * @param value value to consume
705          */
706         void accept(List<T> value);
707     }
708 
709     /** Interface representing instance methods that consume boolean values. */
710     public interface BooleanConsumer {
711         /** Consume a boolean.
712          * @param value value to consume
713          */
714         void accept(boolean value);
715     }
716 
717     /** Interface representing instance methods that consume integer values. */
718     public interface IntConsumer {
719         /** Consume an integer.
720          * @param value value to consume
721          */
722         void accept(int value);
723     }
724 
725     /** Interface representing instance methods that consume integer array. */
726     public interface IntegerArrayConsumer {
727         /** Consume an array of integers.
728          * @param integers array of integers
729          */
730         void accept(int[] integers);
731     }
732 
733     /** Interface representing instance methods that consume character values. */
734     public interface CharConsumer {
735         /** Consume a character.
736          * @param value value to consume
737          */
738         void accept(char value);
739     }
740 
741     /** Interface representing instance methods that consume double values. */
742     public interface DoubleConsumer {
743         /** Consume a double.
744          * @param value value to consume
745          */
746         void accept(double value);
747     }
748 
749     /** Interface representing instance methods that consume labeled double values. */
750     public interface LabeledDoubleConsumer {
751         /** Consume an indexed double.
752          * @param label label
753          * @param value value to consume
754          */
755         void accept(char label, double value);
756     }
757 
758     /** Interface representing instance methods that consume indexed double values. */
759     public interface IndexedDoubleConsumer {
760         /** Consume an indexed double.
761          * @param i index
762          * @param value value to consume
763          */
764         void accept(int i, double value);
765     }
766 
767     /** Interface representing instance methods that consume doubly-indexed double values. */
768     public interface DoublyIndexedDoubleConsumer {
769         /** Consume a doubly indexed double.
770          * @param i first index
771          * @param j second index
772          * @param value value to consume
773          */
774         void accept(int i, int j, double value);
775     }
776 
777     /** Interface representing instance methods that consume vector values. */
778     public interface VectorConsumer {
779         /** Consume a vector.
780          * @param value value to consume
781          */
782         void accept(Vector3D value);
783     }
784 
785     /** Interface representing instance methods that consume date values. */
786     public interface DateConsumer {
787         /** Consume a date.
788          * @param value value to consume
789          */
790         void accept(AbsoluteDate value);
791     }
792 
793     /** Interface representing instance methods that consume time systems values. */
794     public interface TimeSystemConsumer {
795         /** Consume a time system.
796          * @param value value to consume
797          */
798         void accept(TimeSystem value);
799     }
800 
801     /** Interface representing instance methods that consume frame values. */
802     public interface FrameConsumer {
803         /** Consume a frame.
804          * @param frameFacade facade in front of several frames types
805          */
806         void accept(FrameFacade frameFacade);
807     }
808 
809     /** Interface representing instance methods that consume center values. */
810     public interface CenterConsumer {
811         /** Consume a body center.
812          * @param bodyFacade facade for celestial body name and body
813          */
814         void accept(BodyFacade bodyFacade);
815     }
816 
817     /** Interface representing instance methods that consume center lists. */
818     public interface CenterListConsumer {
819         /** Consume a body center.
820          * @param bodyFacades facades for celestial bodies name and bodies
821          */
822         void accept(List<BodyFacade> bodyFacades);
823     }
824 
825     /** Interface representing instance methods that consume units lists values. */
826     public interface UnitListConsumer {
827         /** Consume a list of units.
828          * @param value value to consume
829          */
830         void accept(List<Unit> value);
831     }
832 
833 }