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;
18  
19  import java.io.IOException;
20  
21  import org.orekit.errors.OrekitException;
22  import org.orekit.errors.OrekitInternalError;
23  import org.orekit.errors.OrekitMessages;
24  import org.orekit.files.ccsds.ndm.adm.acm.Acm;
25  import org.orekit.files.ccsds.ndm.adm.aem.Aem;
26  import org.orekit.files.ccsds.ndm.adm.apm.Apm;
27  import org.orekit.files.ccsds.ndm.odm.ocm.Ocm;
28  import org.orekit.files.ccsds.ndm.odm.oem.Oem;
29  import org.orekit.files.ccsds.ndm.odm.omm.Omm;
30  import org.orekit.files.ccsds.ndm.odm.opm.Opm;
31  import org.orekit.files.ccsds.ndm.tdm.Tdm;
32  import org.orekit.files.ccsds.section.Header;
33  import org.orekit.files.ccsds.section.Segment;
34  import org.orekit.files.ccsds.utils.generation.Generator;
35  import org.orekit.files.ccsds.utils.generation.MessageWriter;
36  
37  /**
38   * Writer for CCSDS Navigation Data Message.
39   *
40   * @author Luc Maisonobe
41   * @since 11.0
42   */
43  public class NdmWriter {
44  
45      /** Builder for the constituents writers. */
46      private final WriterBuilder builder;
47  
48      /** Indicator for started message. */
49      private boolean started;
50  
51      /** Number of constituents written. */
52      private int count;
53  
54      /** Simple constructor.
55       * <p>
56       * Calling this constructor directly is not recommended. Users should rather use
57       * {@link org.orekit.files.ccsds.ndm.WriterBuilder#buildNdmWriter()
58       * WriterBuilder.buildNdmWriter()}.
59       * </p>
60       * @param builder builder for the constituents parsers
61       */
62      public NdmWriter(final WriterBuilder builder) {
63          this.builder = builder;
64          this.started = false;
65          this.count   = 0;
66      }
67  
68      /** Write one complete message.
69       * @param generator generator to use for producing output
70       * @param message message to write
71       * @throws IOException if the stream cannot write to stream
72       */
73      public void writeMessage(final Generator generator, final Ndm message)
74          throws IOException {
75  
76          // write the global comments
77          for (final String comment : message.getComments()) {
78              writeComment(generator, comment);
79          }
80  
81          // write the constituents
82          for (final NdmConstituent<?, ?> constituent : message.getConstituents()) {
83              writeConstituent(generator, constituent);
84          }
85  
86      }
87  
88      /** Start the composite message if needed.
89       * @param generator generator to use for producing output
90       * @throws IOException if the stream cannot write to stream
91       */
92      private void startMessageIfNeeded(final Generator generator) throws IOException {
93          if (!started) {
94              generator.enterSection(NdmStructureKey.ndm.name());
95              started = true;
96          }
97      }
98  
99      /** Write a comment line.
100      * <p>
101      * Comments allows comments only before constituents, so attempting to
102      * add comments after the first constituent has been written will
103      * produce an exception.
104      * </p>
105      * @param generator generator to use for producing output
106      * @param comment comment line to write
107      * @throws IOException if the stream cannot write to stream
108      */
109     public void writeComment(final Generator generator, final String comment) throws IOException {
110 
111         startMessageIfNeeded(generator);
112 
113         // check we can still write comments
114         if (count > 0) {
115             throw new OrekitException(OrekitMessages.ATTEMPT_TO_GENERATE_MALFORMED_FILE, generator.getOutputName());
116         }
117 
118         generator.writeEntry(NdmStructureKey.COMMENT.name(), comment, null, false);
119 
120     }
121 
122     /** Write a constituent.
123      * @param generator generator to use for producing output
124      * @param constituent constituent
125      * @param <H> type of the header
126      * @param <S> type of the segments
127      * @param <F> type of the file
128      * @throws IOException if the stream cannot write to stream
129      */
130     public <H extends Header, S extends Segment<?, ?>, F extends NdmConstituent<H, S>>
131         void writeConstituent(final Generator generator, final F constituent) throws IOException {
132 
133         // write the root element if needed
134         startMessageIfNeeded(generator);
135 
136         // write the constituent
137         final MessageWriter<H, S, F> writer = buildWriter(constituent);
138         writer.writeMessage(generator, constituent);
139 
140         // update count
141         ++count;
142 
143     }
144 
145     /** Build writer for a constituent.
146      * @param constituent constituent
147      * @param <H> type of the header
148      * @param <S> type of the segments
149      * @param <F> type of the file
150      * @return writer suited for the constituent
151      * @throws IOException if the stream cannot write to stream
152      */
153     @SuppressWarnings("unchecked")
154     private <H extends Header, S extends Segment<?, ?>, F extends NdmConstituent<H, S>>
155         MessageWriter<H, S, F> buildWriter(final F constituent) throws IOException {
156         if (constituent instanceof Tdm) {
157             return (MessageWriter<H, S, F>) builder.buildTdmWriter();
158         } else if (constituent instanceof Opm) {
159             return (MessageWriter<H, S, F>) builder.buildOpmWriter();
160         } else if (constituent instanceof Omm) {
161             return (MessageWriter<H, S, F>) builder.buildOmmWriter();
162         } else if (constituent instanceof Oem) {
163             return (MessageWriter<H, S, F>) builder.buildOemWriter();
164         } else if (constituent instanceof Ocm) {
165             return (MessageWriter<H, S, F>) builder.buildOcmWriter();
166         } else if (constituent instanceof Apm) {
167             return (MessageWriter<H, S, F>) builder.buildApmWriter();
168         } else if (constituent instanceof Aem) {
169             return (MessageWriter<H, S, F>) builder.buildAemWriter();
170         } else if (constituent instanceof Acm) {
171             return (MessageWriter<H, S, F>) builder.buildAcmWriter();
172         } else {
173             // this should never happen
174             throw new OrekitInternalError(null);
175         }
176     }
177 
178 }