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