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