1   /* Copyright 2002-2025 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.ndm.cdm;
18  
19  import java.util.regex.Matcher;
20  import java.util.regex.Pattern;
21  
22  import org.orekit.files.ccsds.definitions.YesNoUnknown;
23  import org.orekit.files.ccsds.ndm.odm.ocm.ObjectType;
24  import org.orekit.files.ccsds.utils.ContextBinding;
25  import org.orekit.files.ccsds.utils.lexical.ParseToken;
26  import org.orekit.files.ccsds.utils.lexical.TokenType;
27  
28  /** Keys for {@link CdmMetadata CDM container} entries.
29   * @author Melina Vanel
30   * @since 11.2
31   */
32  public enum CdmMetadataKey {
33  
34      /** Object to which data apply. */
35      OBJECT((token, context, container) -> token.processAsNormalizedString(container::setObject)),
36  
37      /** Satellite catalog designator for object. */
38      OBJECT_DESIGNATOR((token, context, container) -> token.processAsNormalizedString(container::setObjectDesignator)),
39  
40      /** Satellite catalog used for the object. */
41      CATALOG_NAME((token, context, container) -> token.processAsNormalizedString(container::setCatalogName)),
42  
43      /** Spacecraft name for the object. */
44      OBJECT_NAME((token, context, container) -> token.processAsNormalizedString(container::setObjectName)),
45  
46      /** Full international designator name for the object. */
47      INTERNATIONAL_DESIGNATOR((token, context, container) -> token.processAsNormalizedString(container::setInternationalDes)),
48  
49      /** Object Type. */
50      OBJECT_TYPE((token, context, container) -> token.processAsEnum(ObjectType.class, container::setObjectType)),
51  
52      /** Contact position of the owner/operator of the object. */
53      OPERATOR_CONTACT_POSITION((token, context, container) -> token.processAsNormalizedString(container::setOperatorContactPosition)),
54  
55      /** Contact organization of the object. */
56      OPERATOR_ORGANIZATION((token, context, container) -> token.processAsNormalizedString(container::setOperatorOrganization)),
57  
58      /** Phone number of the contact position for the object. */
59      OPERATOR_PHONE((token, context, container) -> token.processAsNormalizedString(container::setOperatorPhone)),
60  
61      /** Email address of the contact position for the object. */
62      OPERATOR_EMAIL((token, context, container) -> token.processAsNormalizedString(container::setOperatorEmail)),
63  
64      /** Unique identifier of Orbit Data Message(s) that are linked (relevant) to this Conjunction Data Message. */
65      ODM_MSG_LINK((token, context, container) -> token.processAsFreeTextString(container::setOdmMsgLink)),
66  
67      /** Unique identifier of Attitude Data Message(s) that are linked (relevant) to this Conjunction Data Message. */
68      ADM_MSG_LINK((token, context, container) -> token.processAsFreeTextString(container::setAdmMsgLink)),
69  
70      /** Unique name of the external ephemeris file used for the object or NONE. */
71      EPHEMERIS_NAME((token, context, container) -> token.processAsNormalizedString(container::setEphemName)),
72  
73      /** Flag indicating whether new tracking observations are anticipated prior to the issue of the next CDM associated with the event
74       * specified by CONJUNCTION_ID. */
75      OBS_BEFORE_NEXT_MESSAGE((token, context, container) -> token.processAsEnum(YesNoUnknown.class, container::setObsBeforeNextMessage)),
76  
77      /** Method used to calculate the covariance. */
78      COVARIANCE_METHOD((token, context, container) -> token.processAsEnum(CovarianceMethod.class, container::setCovarianceMethod)),
79  
80      /** The source from which the covariance data used in the report for both Object 1 and Object 2 originates. */
81      COVARIANCE_SOURCE((token, context, container) -> token.processAsNormalizedString(container::setCovarianceSource)),
82  
83      /** Manoeuver capacity. */
84      MANEUVERABLE((token, context, container) -> token.processAsManeuvrableEnum(container::setManeuverable)),
85  
86      /** Central body for Object 1 and 2. */
87      ORBIT_CENTER((token, context, container) -> token.processAsCenter(container::setOrbitCenter,
88                                                                      context.getDataContext().getCelestialBodies())),
89  
90      /** Name of the reference frame, in which state vector data are given. */
91      REF_FRAME((token, context, container) -> token.processAsFrame(container::setRefFrame, context, true, true, true)),
92  
93      /** Flag indicating the type of alternate covariance information provided. */
94      ALT_COV_TYPE((token, context, container) -> token.processAsEnum(AltCovarianceType.class, container::setAltCovType)),
95  
96      /** Name of the reference frame in which the alternate covariance data are given. */
97      ALT_COV_REF_FRAME((token, context, container) -> token.processAsFrame(container::setAltCovRefFrame, context, true, false, false)),
98  
99      /** Gravity model. */
100     GRAVITY_MODEL(new GravityProcessor()),
101 
102     /** Name of atmospheric model. */
103     ATMOSPHERIC_MODEL((token, context, container) -> token.processAsNormalizedString(container::setAtmosphericModel)),
104 
105     /** N-body perturbation bodies. */
106     N_BODY_PERTURBATIONS((token, context, container) -> token.processAsCenterList(container::setNBodyPerturbations,
107                                                                                   context.getDataContext().getCelestialBodies())),
108 
109     /** Is solar radiation pressure used for the OD of the object ? */
110     SOLAR_RAD_PRESSURE((token, context, container) -> token.processAsEnum(YesNoUnknown.class, container::setSolarRadiationPressure)),
111 
112     /** Is solid Earth and ocean tides used for the OD of the object ? */
113     EARTH_TIDES((token, context, container) -> token.processAsEnum(YesNoUnknown.class, container::setEarthTides)),
114 
115     /** Indication of whether in-track thrust modeling used for the object. */
116     INTRACK_THRUST((token, context, container) -> token.processAsEnum(YesNoUnknown.class, container::setIntrackThrust));
117 
118     /** Processing method. */
119     private final transient TokenProcessor processor;
120 
121     /** Simple constructor.
122      * @param processor processing method
123      */
124     CdmMetadataKey(final TokenProcessor processor) {
125         this.processor = processor;
126     }
127 
128     /** Process an token.
129      * @param token token to process
130      * @param context context binding
131      * @param container container to fill
132      * @return true of token was accepted
133      */
134     public boolean process(final ParseToken token, final ContextBinding context, final CdmMetadata container) {
135         return processor.process(token, context, container);
136     }
137 
138     /** Interface for processing one token. */
139     interface TokenProcessor {
140         /** Process one token.
141          * @param token token to process
142          * @param context context binding
143          * @param container container to fill
144          * @return true of token was accepted
145          */
146         boolean process(ParseToken token, ContextBinding context, CdmMetadata container);
147     }
148 
149     /** Dedicated processor for gravity field. */
150     private static class GravityProcessor implements TokenProcessor {
151 
152         /** Pattern for splitting gravity specification. */
153         private static final Pattern GRAVITY_PATTERN =
154                         Pattern.compile("^\\p{Blank}*([-_A-Za-z0-9]+)\\p{Blank}*:" +
155                                         "\\p{Blank}*([0-9]+)D" +
156                                         "\\p{Blank}*([0-9]+)O" +
157                                         "\\p{Blank}*$");
158 
159         /** {@inheritDoc} */
160         @Override
161         public boolean process(final ParseToken token, final ContextBinding context, final CdmMetadata container) {
162             if (token.getType() == TokenType.ENTRY) {
163                 final Matcher matcher = GRAVITY_PATTERN.matcher(token.getContentAsNormalizedString());
164                 if (!matcher.matches()) {
165                     throw token.generateException(null);
166                 }
167                 container.setGravityModel(matcher.group(1),
168                                           Integer.parseInt(matcher.group(2)),
169                                           Integer.parseInt(matcher.group(3)));
170             }
171             return true;
172         }
173     }
174 
175 }