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.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 unitsColumn columns number for aligning units (if negative or zero, units are not output)
57       * @see org.orekit.files.ccsds.ndm.tdm.TdmWriter#KVN_PADDING_WIDTH     TdmWriter.KVN_PADDING_WIDTH
58       * @see org.orekit.files.ccsds.ndm.adm.aem.AemWriter#KVN_PADDING_WIDTH AemWriter.KVN_PADDING_WIDTH
59       * @see org.orekit.files.ccsds.ndm.adm.apm.ApmWriter#KVN_PADDING_WIDTH ApmWriter.KVN_PADDING_WIDTH
60       * @see org.orekit.files.ccsds.ndm.odm.opm.OpmWriter#KVN_PADDING_WIDTH OpmWriter.KVN_PADDING_WIDTH
61       * @see org.orekit.files.ccsds.ndm.odm.omm.OmmWriter#KVN_PADDING_WIDTH OmmWriter.KVN_PADDING_WIDTH
62       * @see org.orekit.files.ccsds.ndm.odm.oem.OemWriter#KVN_PADDING_WIDTH OemWriter.KVN_PADDING_WIDTH
63       * @see org.orekit.files.ccsds.ndm.odm.ocm.OcmWriter#KVN_PADDING_WIDTH OcmWriter.KVN_PADDING_WIDTH
64       */
65      public KvnGenerator(final Appendable output, final int paddingWidth,
66                          final String outputName, final int unitsColumn) {
67          super(output, outputName, unitsColumn > 0);
68          kvFormat = "%-" + FastMath.max(1, paddingWidth) + "s = %s";
69          final StringBuilder builder = new StringBuilder(COMMENT);
70          builder.append(' ');
71          while (builder.length() < paddingWidth + 3) {
72              builder.append(' ');
73          }
74          builder.append("%s%n");
75          this.unitsColumn   = unitsColumn;
76          this.commentFormat = builder.toString();
77      }
78  
79      /** {@inheritDoc} */
80      @Override
81      public FileFormat getFormat() {
82          return FileFormat.KVN;
83      }
84  
85      /** {@inheritDoc} */
86      @Override
87      public void startMessage(final String root, final String messageTypeKey, final double version) throws IOException {
88          writeEntry(messageTypeKey, String.format(AccurateFormatter.STANDARDIZED_LOCALE, "%.1f", version), null, true);
89      }
90  
91      /** {@inheritDoc} */
92      @Override
93      public void endMessage(final String root) {
94          // nothing to do
95      }
96  
97      /** {@inheritDoc} */
98      @Override
99      public void writeComments(final List<String> comments) throws IOException {
100         for (final String comment : comments) {
101             writeRawData(String.format(AccurateFormatter.STANDARDIZED_LOCALE, commentFormat, comment));
102         }
103     }
104 
105     /** {@inheritDoc} */
106     @Override
107     public void writeEntry(final String key, final String value, final Unit unit, final boolean mandatory) throws IOException {
108         if (value == null) {
109             complain(key, mandatory);
110         } else {
111             final String s = String.format(AccurateFormatter.STANDARDIZED_LOCALE, kvFormat, key, value);
112             writeRawData(s);
113             if (writeUnits(unit)) {
114                 for (int column = s.length(); column < unitsColumn; ++column) {
115                     writeRawData(' ');
116                 }
117                 writeRawData('[');
118                 writeRawData(siToCcsdsName(unit.getName()));
119                 writeRawData(']');
120             }
121             newLine();
122         }
123     }
124 
125     /** {@inheritDoc} */
126     @Override
127     public void enterSection(final String name) throws IOException {
128         writeRawData(name);
129         writeRawData(START);
130         newLine();
131         super.enterSection(name);
132     }
133 
134     /** {@inheritDoc} */
135     @Override
136     public String exitSection() throws IOException {
137         final String name = super.exitSection();
138         writeRawData(name);
139         writeRawData(STOP);
140         newLine();
141         return name;
142     }
143 
144 }