1   /* Copyright 2002-2024 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.generation;
18  
19  import java.io.IOException;
20  import java.util.List;
21  
22  import org.hipparchus.util.FastMath;
23  import org.orekit.files.ccsds.utils.FileFormat;
24  import org.orekit.utils.AccurateFormatter;
25  import org.orekit.utils.units.Unit;
26  
27  /** Generator for Key-Value Notation CCSDS messages.
28   * @author Luc Maisonobe
29   * @since 11.0
30   */
31  public class KvnGenerator extends AbstractGenerator {
32  
33      /** Comment keyword. */
34      private static final String COMMENT = "COMMENT";
35  
36      /** Start suffix for sections. */
37      private static final String START = "_START";
38  
39      /** Stop suffix for sections. */
40      private static final String STOP = "_STOP";
41  
42      /** String format used for all key/value pair lines. **/
43      private final String kvFormat;
44  
45      /** Column number for aligning units. */
46      private final int unitsColumn;
47  
48      /** String format used for all comment lines. **/
49      private final String commentFormat;
50  
51      /** Simple constructor.
52       * @param output destination of generated output
53       * @param paddingWidth padding width for aligning the '=' sign
54       * (not counting the extra blank added before the '=' sign)
55       * @param outputName output name for error messages
56       * @param maxRelativeOffset maximum offset in seconds to use relative dates
57       * (if a date is too far from reference, it will be displayed as calendar elements)
58       * @param unitsColumn columns number for aligning units (if negative or zero, units are not output)
59       * @see org.orekit.files.ccsds.ndm.tdm.TdmWriter#KVN_PADDING_WIDTH     TdmWriter.KVN_PADDING_WIDTH
60       * @see org.orekit.files.ccsds.ndm.adm.aem.AemWriter#KVN_PADDING_WIDTH AemWriter.KVN_PADDING_WIDTH
61       * @see org.orekit.files.ccsds.ndm.adm.apm.ApmWriter#KVN_PADDING_WIDTH ApmWriter.KVN_PADDING_WIDTH
62       * @see org.orekit.files.ccsds.ndm.odm.opm.OpmWriter#KVN_PADDING_WIDTH OpmWriter.KVN_PADDING_WIDTH
63       * @see org.orekit.files.ccsds.ndm.odm.omm.OmmWriter#KVN_PADDING_WIDTH OmmWriter.KVN_PADDING_WIDTH
64       * @see org.orekit.files.ccsds.ndm.odm.oem.OemWriter#KVN_PADDING_WIDTH OemWriter.KVN_PADDING_WIDTH
65       * @see org.orekit.files.ccsds.ndm.odm.ocm.OcmWriter#KVN_PADDING_WIDTH OcmWriter.KVN_PADDING_WIDTH
66       */
67      public KvnGenerator(final Appendable output, final int paddingWidth,
68                          final String outputName, final double maxRelativeOffset,
69                          final int unitsColumn) {
70          super(output, outputName, maxRelativeOffset, unitsColumn > 0);
71          kvFormat = "%-" + FastMath.max(1, paddingWidth) + "s = %s";
72          final StringBuilder builder = new StringBuilder(COMMENT);
73          builder.append(' ');
74          while (builder.length() < paddingWidth + 3) {
75              builder.append(' ');
76          }
77          builder.append("%s%n");
78          this.unitsColumn   = unitsColumn;
79          this.commentFormat = builder.toString();
80      }
81  
82      /** {@inheritDoc} */
83      @Override
84      public FileFormat getFormat() {
85          return FileFormat.KVN;
86      }
87  
88      /** {@inheritDoc} */
89      @Override
90      public void startMessage(final String root, final String messageTypeKey, final double version) throws IOException {
91          writeEntry(messageTypeKey, String.format(AccurateFormatter.STANDARDIZED_LOCALE, "%.1f", version), null, true);
92      }
93  
94      /** {@inheritDoc} */
95      @Override
96      public void endMessage(final String root) {
97          // nothing to do
98      }
99  
100     /** {@inheritDoc} */
101     @Override
102     public void writeComments(final List<String> comments) throws IOException {
103         for (final String comment : comments) {
104             writeRawData(String.format(AccurateFormatter.STANDARDIZED_LOCALE, commentFormat, comment));
105         }
106     }
107 
108     /** {@inheritDoc} */
109     @Override
110     public void writeEntry(final String key, final String value, final Unit unit, final boolean mandatory) throws IOException {
111         if (value == null) {
112             complain(key, mandatory);
113         } else {
114             final String s = String.format(AccurateFormatter.STANDARDIZED_LOCALE, kvFormat, key, value);
115             writeRawData(s);
116             if (writeUnits(unit)) {
117                 for (int column = s.length(); column < unitsColumn; ++column) {
118                     writeRawData(' ');
119                 }
120                 writeRawData('[');
121                 writeRawData(siToCcsdsName(unit.getName()));
122                 writeRawData(']');
123             }
124             newLine();
125         }
126     }
127 
128     /** {@inheritDoc} */
129     @Override
130     public void enterSection(final String name) throws IOException {
131         writeRawData(name);
132         writeRawData(START);
133         newLine();
134         super.enterSection(name);
135     }
136 
137     /** {@inheritDoc} */
138     @Override
139     public String exitSection() throws IOException {
140         final String name = super.exitSection();
141         writeRawData(name);
142         writeRawData(STOP);
143         newLine();
144         return name;
145     }
146 
147 }