1   /* Copyright 2024-2025 The Johns Hopkins University Applied Physics Laboratory
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.iirv;
18  
19  import org.orekit.errors.OrekitIllegalStateException;
20  import org.orekit.errors.OrekitInternalError;
21  import org.orekit.errors.OrekitMessages;
22  import org.orekit.files.iirv.terms.CheckSumTerm;
23  import org.orekit.files.iirv.terms.CoordinateSystemTerm;
24  import org.orekit.files.iirv.terms.CrossSectionalAreaTerm;
25  import org.orekit.files.iirv.terms.DataSourceTerm;
26  import org.orekit.files.iirv.terms.DayOfYearTerm;
27  import org.orekit.files.iirv.terms.DragCoefficientTerm;
28  import org.orekit.files.iirv.terms.MassTerm;
29  import org.orekit.files.iirv.terms.MessageClassTerm;
30  import org.orekit.files.iirv.terms.MessageEndConstantTerm;
31  import org.orekit.files.iirv.terms.MessageIDTerm;
32  import org.orekit.files.iirv.terms.MessageSourceTerm;
33  import org.orekit.files.iirv.terms.MessageStartConstantTerm;
34  import org.orekit.files.iirv.terms.MessageTypeTerm;
35  import org.orekit.files.iirv.terms.OriginIdentificationTerm;
36  import org.orekit.files.iirv.terms.OriginatorRoutingIndicatorTerm;
37  import org.orekit.files.iirv.terms.PositionVectorComponentTerm;
38  import org.orekit.files.iirv.terms.RoutingIndicatorTerm;
39  import org.orekit.files.iirv.terms.SequenceNumberTerm;
40  import org.orekit.files.iirv.terms.SolarReflectivityCoefficientTerm;
41  import org.orekit.files.iirv.terms.SpareConstantTerm;
42  import org.orekit.files.iirv.terms.SupportIdCodeTerm;
43  import org.orekit.files.iirv.terms.VectorEpochTerm;
44  import org.orekit.files.iirv.terms.VectorTypeTerm;
45  import org.orekit.files.iirv.terms.VehicleIdCodeTerm;
46  import org.orekit.files.iirv.terms.VelocityVectorComponentTerm;
47  
48  import java.util.ArrayList;
49  import java.util.Arrays;
50  import java.util.List;
51  import java.util.Objects;
52  
53  /**
54   * Container for Improved Interrange Vector (IIRV) messages, implemented as a list of sequential {@link IIRVVector}
55   * instances.
56   * <p>
57   * The IIRV message consists of a series of sequential {@link IIRVVector}s that each contains ephemeris state data
58   * at a particular epoch. The message body is defined as:<p>
59   * {@code ttuuuuuuuqjjGIIRVarrrr<<≡≡}<br>
60   * {@code vs1ciiiibbnnndoyhhmmsssssccc<<≡≡}<br>
61   * {@code sxxxxxxxxxxxxsyyyyyyyyyyyyszzzzzzzzzzzzccc<<==}<br>
62   * {@code sxxxxxxxxxxxxsyyyyyyyyyyyyszzzzzzzzzzzzccc<<==}<br>
63   * {@code mmmmmmmmaaaaakkkksrrrrrrrccc<<==}<br>
64   * {@code ITERM oooo<<==}
65   * <table border="1">
66   *    <caption>Line No. / Characters / Value / Type / Description / Class</caption>
67   *    <tbody>
68   *        <tr>
69   *            <th rowspan="9">1</th>
70   *            <td>{@code tt}</td>
71   *            <td>2 characters</td>
72   *            <td>Constant</td>
73   *            <td>Message Type (Operations Data Message)</td>
74   *            <td>{@link MessageTypeTerm}</td>
75   *        <tr>
76   *            <td>{@code uuuuuuu}</td>
77   *            <td>0000000 to 9999999</td>
78   *            <td>Integer</td>
79   *            <td>Message ID</td>
80   *            <td>{@link MessageIDTerm}</td>
81   *        <tr>
82   *            <td>{@code q}</td>
83   *            <td>1 character</td>
84   *            <td>String</td>
85   *            <td>Message Source</td>
86   *            <td>{@link MessageSourceTerm}</td>
87   *        <tr>
88   *            <td>{@code jj}</td>
89   *            <td>
90   *                <ul>
91   *                <li> 10 = Nominal
92   *                <li> 15 = In-flight Update
93   *                </ul></td>
94   *            <td>String</td>
95   *            <td>Message class (10=nominal)</td>
96   *            <td>{@link MessageClassTerm}</td>
97   *        <tr>
98   *            <td>{@code GIIRV}</td>
99   *            <td>"GIIRV"</td>
100  *            <td>Constant</td>
101  *            <td>Message ID</td>
102  *            <td>{@link MessageStartConstantTerm}</td>
103  *        <tr>
104  *            <td>{@code a}</td>
105  *            <td>
106  *                <ul>
107  *                <li> ASCII space  = GSFC
108  *                <li> Z            = WLP
109  *                <li> E            = ETR
110  *                <li> L            = JPL
111  *                <li> W            = WTR
112  *                <li> J            = JSC
113  *                <li> P            = PMR
114  *                <li> A            = CSTC
115  *                <li> K            = KMR
116  *                <li> C            = CNES
117  *                </ul></td>
118  *            <td>String</td>
119  *            <td>Origin identification</td>
120  *            <td>{@link OriginIdentificationTerm}</td>
121  *        <tr>
122  *            <td>{@code rrrr}</td>
123  *            <td>
124  *                <ul>
125  *                <li>GSFC    = NASA Goddard Space Flight Center
126  *                <li>WLP     = Wallops Island tracking radars
127  *                <li>ETR     = NASA/USFC Eastern Test Range
128  *                <li>JPL     = NASA Jet Propulsion Laboratory
129  *                <li>WTR     = NASA/USFC Western Test Range
130  *                <li>JSC     = NASA Johnson Space Center
131  *                <li>PMR     = Navy Pacific Missile Range
132  *                <li>CSTC    = Air Force Satellite Control Facility
133  *                <li>KMR     = Army Kwajalein Missile Range
134  *                <li>CNES    = French Space Agency National <br>Centre for Space Studies (CNES)
135  *                <li>MANY    = Message originated from more <br>than one of the above stations
136  *                </ul></td>
137  *            <td>String</td>
138  *            <td>Destination routing indicator</td>
139  *            <td>{@link RoutingIndicatorTerm}</td>
140  *        <tr>
141  *            <td>{@code <<}</td>
142  *            <td>"\r\r"</td>
143  *            <td>Constant</td>
144  *            <td>Carriage returns</td>
145  *            <td>n/a</td>
146  *        <tr>
147  *            <td>==</td>
148  *            <td>"\n\n"</td>
149  *            <td>Constant</td>
150  *            <td>Line feeds</td>
151  *            <td>n/a</td>
152  *        <tr>
153  *            <th rowspan="12">2</th>
154  *            <td>{@code v}</td>
155  *            <td>
156  *                <ul>
157  *                <li> 1 = Free flight (routine on-orbit)
158  *                <li> 2 = Forced (special orbit update)
159  *                <li> 3 = Spare
160  *                <li> 4 = Maneuver ignition
161  *                <li> 5 = Maneuver cutoff
162  *                <li> 6 = Reentry
163  *                <li> 7 = Powered flight
164  *                <li> 8 = Stationary
165  *                <li> 9 = Spare
166  *                </ul></td>
167  *            <td>Integer</td>
168  *            <td>Vector type</td>
169  *            <td>{@link VectorTypeTerm}</td>
170  *        <tr>
171  *            <td>{@code s}</td>
172  *            <td>
173  *                <ul>
174  *                <li> 1 = Nominal/planning
175  *                <li> 2 = Real-time
176  *                <li> 3 = Off-line
177  *                <li> 4 = Off-line/mean
178  *                </ul></td>
179  *            <td>Integer</td>
180  *            <td>Source of data</td>
181  *            <td>{@link DataSourceTerm}</td>
182  *        <tr>
183  *            <td>{@code 1}</td>
184  *            <td>"1" = interrange message</td>
185  *            <td>Constant</td>
186  *            <td>Transfer type</td>
187  *            <td>{@link org.orekit.files.iirv.terms.TransferTypeConstantTerm}</td>
188  *        <tr>
189  *            <td>{@code c}</td>
190  *            <td>
191  *                <ul>
192  *                <li> 1 = Geocentric True-of-Date Rotating
193  *                <li> 2 = Geocentric mean of 1950.0 (B1950.0)
194  *                <li> 3 = Heliocentric B1950.0
195  *                <li> 4 = Reserved for JPL use (non-GSFC)
196  *                <li> 5 = Reserved for JPL use (non-GSFC)
197  *                <li> 6 = Geocentric mean of 2000.0 (J2000.0)
198  *                <li> 7 = Heliocentric J2000.0
199  *                </ul></td>
200  *            <td>Integer</td>
201  *            <td>Coordinate system</td>
202  *            <td>{@link CoordinateSystemTerm}</td>
203  *        <tr>
204  *            <td>{@code iiii}</td>
205  *            <td>0000-9999</td>
206  *            <td>Integer</td>
207  *            <td>Support Identification Code (SIC)</td>
208  *            <td>{@link SupportIdCodeTerm}</td>
209  *        <tr>
210  *            <td>{@code bb}</td>
211  *            <td>00-99</td>
212  *            <td>Integer</td>
213  *            <td>Vehicle Identification Code (VIC)</td>
214  *            <td>{@link VehicleIdCodeTerm}</td>
215  *        <tr>
216  *            <td>{@code nnn}</td>
217  *            <td>000-999</td>
218  *            <td>Integer</td>
219  *            <td>Sequence number</td>
220  *            <td>{@link SequenceNumberTerm}</td>
221  *        <tr>
222  *            <td>{@code doy}</td>
223  *            <td>001-366</td>
224  *            <td>Integer</td>
225  *            <td>Day of year</td>
226  *            <td>{@link DayOfYearTerm}</td>
227  *        <tr>
228  *            <td>{@code hhmmsssss}</td>
229  *            <td>000000000 - 235959999</td>
230  *            <td>Integer</td>
231  *            <td>Vector epoch (in UTC)<br>HH:mm:ss.SSS</td>
232  *            <td>{@link VectorEpochTerm}</td>
233  *        <tr>
234  *            <td>{@code ccc}</td>
235  *            <td>000-999</td>
236  *            <td>Integer</td>
237  *            <td>Checksum for line 2</td>
238  *            <td>{@link CheckSumTerm}</td>
239  *        <tr>
240  *            <td>{@code <<}</td>
241  *            <td>"\r\r"</td>
242  *            <td>Constant</td>
243  *            <td>Carriage returns</td>
244  *            <td>n/a</td>
245  *        <tr>
246  *            <td>==</td>
247  *            <td>"\n\n"</td>
248  *            <td>Constant</td>
249  *            <td>Line feeds</td>
250  *            <td>n/a</td>
251  *        <tr>
252  *            <th rowspan="7">3</th>
253  *            <td>{@code s}</td>
254  *            <td>
255  *                <ul>
256  *                <li> " " (ASCII Space) = positive
257  *                <li> "-" = Negative
258  *                </ul></td>
259  *            <td>Integer</td>
260  *            <td>Positive/negative sign</td>
261  *            <td>n/a</td>
262  *        <tr>
263  *            <td>{@code xxxxxxxxxxxx}</td>
264  *            <td>0 - 9999999999999</td>
265  *            <td>Integer</td>
266  *            <td>X component of position (m)</td>
267  *            <td>{@link PositionVectorComponentTerm}</td>
268  *        <tr>
269  *            <td>{@code yyyyyyyyyyyy}</td>
270  *            <td>0 - 9999999999999</td>
271  *            <td>Integer</td>
272  *            <td>Y component of position (m)</td>
273  *            <td>{@link PositionVectorComponentTerm}</td>
274  *        <tr>
275  *            <td>{@code zzzzzzzzzzzz}</td>
276  *            <td>0 - 9999999999999</td>
277  *            <td>Integer</td>
278  *            <td>Z component of position (m)</td>
279  *            <td>{@link PositionVectorComponentTerm}</td>
280  *        <tr>
281  *            <td>{@code ccc}</td>
282  *            <td>000-999</td>
283  *            <td>Integer</td>
284  *            <td>Checksum for line 3</td>
285  *            <td>{@link CheckSumTerm}</td>
286  *        <tr>
287  *            <td>{@code <<}</td>
288  *            <td>"\r\r"</td>
289  *            <td>Constant</td>
290  *            <td>Carriage returns</td>
291  *            <td>n/a</td>
292  *        <tr>
293  *            <td>==</td>
294  *            <td>"\n\n"</td>
295  *            <td>Constant</td>
296  *            <td>Line feeds</td>
297  *            <td>n/a</td>
298  *        <tr>
299  *            <th rowspan="7">4</th>
300  *            <td>{@code s}</td>
301  *            <td>
302  *                <ul>
303  *                <li> " " (ASCII Space) = positive
304  *                <li> "-" = Negative
305  *                </ul></td>
306  *            <td>Integer</td>
307  *            <td>Positive/negative sign</td>
308  *            <td>n/a</td>
309  *        <tr>
310  *            <td>{@code xxxxxxxxxxxx}</td>
311  *            <td>0 - 9999999999.999</td>
312  *            <td>Double</td>
313  *            <td>X component of velocity (m/s)</td>
314  *            <td>{@link VelocityVectorComponentTerm}</td>
315  *        <tr>
316  *            <td>{@code yyyyyyyyyyyy}</td>
317  *            <td>0 - 9999999999.999</td>
318  *            <td>Double</td>
319  *            <td>Y component of velocity (m/s)</td>
320  *            <td>{@link VelocityVectorComponentTerm}</td>
321  *        <tr>
322  *            <td>{@code zzzzzzzzzzzz}</td>
323  *            <td>0 - 9999999999.999</td>
324  *            <td>Double</td>
325  *            <td>Z component of velocity (m/s)</td>
326  *            <td>{@link VelocityVectorComponentTerm}</td>
327  *        <tr>
328  *            <td>{@code ccc}</td>
329  *            <td>000-999</td>
330  *            <td>Integer</td>
331  *            <td>Checksum for line 4</td>
332  *            <td>{@link CheckSumTerm}</td>
333  *        <tr>
334  *            <td>{@code <<}</td>
335  *            <td>"\r\r"</td>
336  *            <td>Constant</td>
337  *            <td>Carriage returns</td>
338  *            <td>n/a</td>
339  *        <tr>
340  *            <td>==</td>
341  *            <td>"\n\n"</td>
342  *            <td>Constant</td>
343  *            <td>Line feeds</td>
344  *            <td>n/a</td>
345  *        <tr>
346  *            <th rowspan="7">5</th>
347  *            <td>{@code mmmmmmmm}</td>
348  *            <td>0 - 99999999.9</td>
349  *            <td>Double</td>
350  *            <td>Spacecraft mass (kg)</td>
351  *            <td>{@link MassTerm}</td>
352  *        <tr>
353  *            <td>{@code aaaaa}</td>
354  *            <td>0 - 999.99</td>
355  *            <td>Double</td>
356  *            <td>Average cross-sectional area (m^2)</td>
357  *            <td>{@link CrossSectionalAreaTerm}</td>
358  *        <tr>
359  *            <td>{@code kkkk}</td>
360  *            <td>0 - 99.99</td>
361  *            <td>Double</td>
362  *            <td>Drag coefficient (dimensionless)</td>
363  *            <td>{@link DragCoefficientTerm}</td>
364  *        <tr>
365  *            <td>{@code srrrrrrr}</td>
366  *            <td>-99.99999 to 99.99999</td>
367  *            <td>Double</td>
368  *            <td>Solar reflectivity coefficient (dimensionless)</td>
369  *            <td>{@link SolarReflectivityCoefficientTerm}</td>
370  *        <tr>
371  *            <td>{@code ccc}</td>
372  *            <td>000-999</td>
373  *            <td>Integer</td>
374  *            <td>Checksum for line 5</td>
375  *            <td>{@link CheckSumTerm}</td>
376  *        <tr>
377  *            <td>{@code <<}</td>
378  *            <td>"\r\r"</td>
379  *            <td>Constant</td>
380  *            <td>Carriage returns</td>
381  *            <td>n/a</td>
382  *        <tr>
383  *            <td>==</td>
384  *            <td>"\n\n"</td>
385  *            <td>Constant</td>
386  *            <td>Line feeds</td>
387  *            <td>n/a</td>
388  *        <tr>
389  *            <th rowspan="5">6</th>
390  *            <td>{@code ITERM}</td>
391  *            <td>"ITERM"</td>
392  *            <td>Constant</td>
393  *            <td>End of message</td>
394  *            <td>{@link MessageEndConstantTerm}</td>
395  *        <tr>
396  *            <td>{@code ITERM}</td>
397  *            <td>ASCII Space</td>
398  *            <td>Constant</td>
399  *            <td>Spare (blank) character</td>
400  *            <td>{@link SpareConstantTerm}</td>
401  *        <tr>
402  *            <td>{@code oooo}</td>
403  *            <td>"GCQU" or "GAQD"</td>
404  *            <td>String</td>
405  *            <td>Originator routing indicator</td>
406  *            <td>{@link OriginatorRoutingIndicatorTerm}</td>
407  *        <tr>
408  *            <td>{@code <<}</td>
409  *            <td>"\r\r"</td>
410  *            <td>Constant</td>
411  *            <td>Carriage returns</td>
412  *            <td>n/a</td>
413  *        <tr>
414  *            <td>==</td>
415  *            <td>"\n\n"</td>
416  *            <td>Constant</td>
417  *            <td>Line feeds</td>
418  *            <td>n/a</td>
419  *        <tr>
420  *            <th>7-12</th>
421  *            <td colspan="5">Second {@link IIRVVector} in message</td>
422  *        <tr>
423  *            <th>13-18</th>
424  *            <td colspan="5">Third {@link IIRVVector} in message</td>
425  *        <tr>
426  *            <th>...</th>
427  *            <td colspan="5">nth {@link IIRVVector} in message</td>
428  *    </tbody>
429  * </table>
430  *
431  * @author Nick LaFarge
432  * @since 13.0
433  */
434 public class IIRVMessage {
435 
436     /** List of vectors that comprise the IIRV message. */
437     private final List<IIRVVector> vectors;
438 
439     /** Constructor that initializes to an empty list of vectors. */
440     public IIRVMessage() {
441         this.vectors = new ArrayList<>();
442     }
443 
444     /**
445      * Constructor from a list of IIRV {@link IIRVVector}s that monotonically increase in both
446      * {@link org.orekit.files.iirv.terms.SequenceNumberTerm} and time ({@link org.orekit.files.iirv.terms.DayOfYearTerm}
447      * and {@link org.orekit.files.iirv.terms.VectorEpochTerm}).
448      *
449      * @param vectors list of sequential {@link IIRVVector}s.
450      */
451     public IIRVMessage(final List<IIRVVector> vectors) {
452         // Perform validation checks
453         validateSequenceNumberIncreasing(vectors);
454         validateStaticValues(vectors);
455 
456         this.vectors = vectors;
457     }
458 
459     /**
460      * Constructor from a list of IIRV {@link IIRVVector}s that monotonically increase in both
461      * {@link org.orekit.files.iirv.terms.SequenceNumberTerm} and time ({@link org.orekit.files.iirv.terms.DayOfYearTerm}
462      * and {@link org.orekit.files.iirv.terms.VectorEpochTerm}).
463      *
464      * @param vectors list of sequential IIRV vectors.
465      */
466     public IIRVMessage(final IIRVVector... vectors) {
467         this(Arrays.asList(vectors));
468     }
469 
470     /**
471      * Copy constructor.
472      *
473      * @param other other {@link IIRVMessage} instance.
474      */
475     public IIRVMessage(final IIRVMessage other) {
476         final List<IIRVVector> copied_vectors = new ArrayList<>();
477         for (IIRVVector v : other.getVectors()) {
478             copied_vectors.add(new IIRVVector(v));
479         }
480         validateSequenceNumberIncreasing(copied_vectors);
481         validateStaticValues(copied_vectors);
482         this.vectors = copied_vectors;
483     }
484 
485     @Override
486     public boolean equals(final Object o) {
487         if (this == o) {
488             return true;
489         }
490         if (o == null || getClass() != o.getClass()) {
491             return false;
492         }
493         final IIRVMessage that = (IIRVMessage) o;
494         return Objects.equals(toMessageString(IncludeMessageMetadata.ALL_VECTORS), that.toMessageString(IncludeMessageMetadata.ALL_VECTORS));
495     }
496 
497     @Override
498     public int hashCode() {
499         return Objects.hashCode(vectors);
500     }
501 
502     /**
503      * Adds an {@link IIRVVector} to the message (see {@link ArrayList#add(Object)}).
504      *
505      * @param v IIRV vector to add to the message
506      */
507     public void add(final IIRVVector v) {
508         if (vectors.isEmpty()) {
509             vectors.add(v);
510             return;
511         }
512 
513         // Check that the time and sequence number are increasing
514         final int prevLineNumber = vectors.size() - 1;
515         final IIRVVector prev = vectors.get(prevLineNumber);
516 
517         // Verify sequence number is increasing by one
518         if (prev.getSequenceNumber().value() + 1 != v.getSequenceNumber().value()) {
519             throw new OrekitIllegalStateException(OrekitMessages.IIRV_SEQUENCE_NUMBER_MUST_BE_INCREASING_BY_ONE, prevLineNumber, prev.getSequenceNumber().value(), prevLineNumber, v.getSequenceNumber().value());
520         }
521 
522         // Ensure the static values are consistent across all the vectors
523         validateStaticValues(vectors);
524 
525         this.vectors.add(v);
526     }
527 
528     /**
529      * Gets the {@link IIRVVector} located at a given index in the message.
530      *
531      * @param i index of the element to return
532      * @return element at the given index
533      * @see ArrayList#get(int)
534      */
535     public IIRVVector get(final int i) {
536         return vectors.get(i);
537     }
538 
539     /**
540      * Returns the number of IIRV vectors contained in the message.
541      *
542      * @return number of IIRV vectors contained in the message
543      * @see ArrayList#size()
544      */
545     public int size() {
546         return vectors.size();
547     }
548 
549     /**
550      * Returns true if no vectors exist in the message.
551      *
552      * @return true if no vectors exist in the message
553      * @see ArrayList#isEmpty()
554      */
555     public boolean isEmpty() {
556         return vectors.isEmpty();
557     }
558 
559     /**
560      * Converts the {@link IIRVVector}s contained in the message file into a list of their String representations.
561      *
562      * @param includeMessageMetadataSetting Setting for when message metadata terms appear in the created IIRV message
563      * @return list of {@link IIRVVector} strings for each vector the message
564      * @see IIRVVector#toIIRVString
565      */
566     public ArrayList<String> getVectorStrings(final IncludeMessageMetadata includeMessageMetadataSetting) {
567         final ArrayList<String> messageStrings = new ArrayList<>();
568         for (int i = 0; i < vectors.size(); i++) {
569             final boolean includeMessageMetadata;
570             switch (includeMessageMetadataSetting) {
571                 case ALL_VECTORS: {
572                     includeMessageMetadata = true;
573                     break;
574                 }
575                 case FIRST_VECTOR_ONLY: {
576                     includeMessageMetadata = i == 0;
577                     break;
578                 }
579                 default:
580                     throw new OrekitInternalError(null);
581             }
582             messageStrings.add(vectors.get(i).toIIRVString(includeMessageMetadata));
583         }
584 
585         return messageStrings;
586     }
587 
588     /**
589      * Converts the {@link IIRVVector}s contained in the message file into a single String, where no deliminator
590      * included between each vector (the vectors already have trailing line carriage and line returns).
591      *
592      * @param includeMessageMetadataSetting Setting for when message metadata terms appear in the created IIRV message
593      * @return String containing all {@link IIRVVector}s for the IIRV message
594      * @see IIRVVector#toIIRVString
595      */
596     public String toMessageString(final IncludeMessageMetadata includeMessageMetadataSetting) {
597         return String.join("", getVectorStrings(includeMessageMetadataSetting));
598     }
599 
600     /**
601      * Gets the list of sequential {@link IIRVVector} instances contained within the overall IIRV message.
602      *
603      * @return list of sequential {@link IIRVVector} instances contained within the overall IIRV message.
604      */
605     public List<IIRVVector> getVectors() {
606         return vectors;
607     }
608 
609     /**
610      * Validates that values that are expected to remain constant do not change across a series of inputted
611      * IIRV vectors.
612      *
613      * @param iirvVectors List of {@link IIRVVector} instances to validate.
614      */
615     private void validateStaticValues(final List<IIRVVector> iirvVectors) {
616 
617         // Check thatM select values are consistent across entire vector
618         final IIRVVector firstIIRV = iirvVectors.get(0);
619         for (int i = 1; i < iirvVectors.size(); i++) {
620             final IIRVVector iirv = iirvVectors.get(i);
621 
622             // Check that terms you expect to remain constant, do remain constant
623             if (!firstIIRV.getMessageID().equals(iirv.getMessageID())) {
624                 throw new OrekitIllegalStateException(OrekitMessages.IIRV_TERM_CHANGES_WITHIN_FILE, "Message ID");
625             } else if (!firstIIRV.getMessageClass().equals(iirv.getMessageClass())) {
626                 throw new OrekitIllegalStateException(OrekitMessages.IIRV_TERM_CHANGES_WITHIN_FILE, "Message class");
627             } else if (!firstIIRV.getOriginIdentification().equals(iirv.getOriginIdentification())) {
628                 throw new OrekitIllegalStateException(OrekitMessages.IIRV_TERM_CHANGES_WITHIN_FILE, "Origin ID");
629             } else if (!firstIIRV.getRoutingIndicator().equals(iirv.getRoutingIndicator())) {
630                 throw new OrekitIllegalStateException(OrekitMessages.IIRV_TERM_CHANGES_WITHIN_FILE, "Routing indicator");
631             } else if (!firstIIRV.getVectorType().equals(iirv.getVectorType())) {
632                 throw new OrekitIllegalStateException(OrekitMessages.IIRV_TERM_CHANGES_WITHIN_FILE, "Vector type");
633             } else if (!firstIIRV.getDataSource().equals(iirv.getDataSource())) {
634                 throw new OrekitIllegalStateException(OrekitMessages.IIRV_TERM_CHANGES_WITHIN_FILE, "Data source");
635             } else if (!firstIIRV.getCoordinateSystem().equals(iirv.getCoordinateSystem())) {
636                 throw new OrekitIllegalStateException(OrekitMessages.IIRV_TERM_CHANGES_WITHIN_FILE, "Coordinate system");
637             } else if (!firstIIRV.getSupportIdCode().equals(iirv.getSupportIdCode())) {
638                 throw new OrekitIllegalStateException(OrekitMessages.IIRV_TERM_CHANGES_WITHIN_FILE, "Support ID code (SIC)");
639             } else if (!firstIIRV.getVehicleIdCode().equals(iirv.getVehicleIdCode())) {
640                 throw new OrekitIllegalStateException(OrekitMessages.IIRV_TERM_CHANGES_WITHIN_FILE, "Vehicle ID code (VID)");
641             }
642         }
643     }
644 
645     /**
646      * Returns the satellite ID (set to the value of the {@link org.orekit.files.iirv.terms.VehicleIdCodeTerm}).
647      *
648      * @return the satellite ID
649      * @see org.orekit.files.iirv.terms.VehicleIdCodeTerm
650      */
651     public String getSatelliteID() {
652         return vectors.get(0).getVehicleIdCode().toEncodedString();
653     }
654 
655     /**
656      * Validates that the sequence number increases by one for each element in a series of {@link IIRVVector}s.
657      *
658      * @param iirvVectors List of {@link IIRVVector} instances to validate.
659      */
660     private void validateSequenceNumberIncreasing(final List<IIRVVector> iirvVectors) {
661         if (iirvVectors.size() < 2) {
662             return;
663         }
664 
665         // Check that sequence number increases by 1 each time
666         for (int i = 1; i < iirvVectors.size(); i++) {
667             final IIRVVector current = iirvVectors.get(i);
668             final IIRVVector prev = iirvVectors.get(i - 1);
669             if (current.getSequenceNumber().value() - prev.getSequenceNumber().value() != 1) {
670                 throw new OrekitIllegalStateException(OrekitMessages.IIRV_SEQUENCE_NUMBER_MUST_BE_INCREASING_BY_ONE, i - 1, prev.getSequenceNumber().value(), current.getSequenceNumber().value());
671             }
672         }
673     }
674 
675     /**
676      * Options for how message metadata appears in the IIRV message file.
677      * <p>
678      * Message metadata fields refer to the first four terms defined for an IIRV vector:
679      * <ul>
680      *     <li>{@link MessageTypeTerm}</li>
681      *     <li>{@link org.orekit.files.iirv.terms.MessageIDTerm}</li>
682      *     <li>{@link MessageSourceTerm}</li>
683      *     <li>{@link org.orekit.files.iirv.terms.MessageClassTerm}</li>
684      * </ul>
685      *
686      * @author Nick LaFarge
687      * @since 13.0
688      */
689     public enum IncludeMessageMetadata {
690         /**
691          * Include message metadata fields in the first line of the first vector
692          * (when {@link org.orekit.files.iirv.terms.SequenceNumberTerm} is 0), and omit for all other vectors
693          * in a given IIRV message file.
694          */
695         FIRST_VECTOR_ONLY,
696 
697         /** Include message metadata fields from all vectors in a given IIRV message file. */
698         ALL_VECTORS
699     }
700 
701 }