1 /* Copyright 2024-2025 The Johns Hopkins University Applied Physics Laboratory
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.iirv.terms.base;
18
19 import org.hipparchus.util.FastMath;
20 import org.orekit.errors.OrekitIllegalArgumentException;
21 import org.orekit.errors.OrekitMessages;
22
23 import java.util.regex.Pattern;
24
25 /**
26 * Term in an IIRV Vector representing a Long (or integer) value.
27 *
28 * @author Nick LaFarge
29 * @since 13.0
30 */
31 public class LongValuedIIRVTerm extends IIRVVectorTerm<Long> {
32
33 /** Space pattern. */
34 private static final Pattern SPACE_PATTERN = Pattern.compile(" ");
35
36 /** True if negative values are permitted, false if the value is positive. */
37 private final boolean isSigned;
38
39 /**
40 * Constructs an IIRV Vector Term represented by a long. This representation is used for any numeric terms
41 * in the IIRV Vector that do not contain a decimal point.
42 *
43 * @param pattern Regular expression pattern that validates the term
44 * @param value Value of the term, expressed as a long
45 * @param length LengthC of the term, measured in number of characters in the String representation
46 * @param isSigned True if negative values are permitted, false if the value is positive
47 */
48 public LongValuedIIRVTerm(final String pattern, final long value, final int length, final boolean isSigned) {
49 super(pattern, value, length);
50 this.isSigned = isSigned;
51 validateString(toEncodedString(value));
52 validateNumericValue(this.value());
53 }
54
55 /**
56 * Constructs an IIRV Vector Term represented by a Long. This representation is used for any numeric terms
57 * in the IIRV Vector that do not contain a decimal point.
58 *
59 * @param pattern Regular expression pattern that validates the term
60 * @param value Value of the term, expressed as a String
61 * @param length Length of the term, measured in number of characters in the String representation
62 * @param isSigned True if negative values are permitted, false if the value is positive
63 */
64 public LongValuedIIRVTerm(final String pattern, final String value, final int length, final boolean isSigned) {
65 super(pattern, LongValuedIIRVTerm.computeValueFromString(value), length);
66 this.isSigned = isSigned;
67 validateString(value);
68 validateNumericValue(this.value());
69 }
70
71 /**
72 * Parses a string as a long, removing any leading spaces.
73 *
74 * @param value String value of the term.
75 * @return the long represented by the argument
76 */
77 public static long computeValueFromString(final String value) {
78 try {
79 // Remove spaces (for positive values)
80 final String integerString = SPACE_PATTERN.matcher(value).replaceAll("");
81
82 // Cast String to integer
83 return Long.parseLong(integerString);
84 } catch (NumberFormatException nfe) {
85 throw new OrekitIllegalArgumentException(OrekitMessages.IIRV_INVALID_TERM_VALUE, value);
86 }
87 }
88
89 /** {@inheritDoc} */
90 @Override
91 public String toEncodedString(final Long termValue) {
92
93 // Reserve one character for the sign (if applicable)
94 final int signAdjustedStringLength = isSigned ? length() - 1 : length();
95
96 String signCharacter = ""; // Sign character ('' for unsigned number)
97 if (isSigned) {
98 signCharacter = termValue > 0 ? " " : "-";
99 }
100
101 // Pad each string with zeros to reach the desired length
102 final String integerString = String.format("%0" + signAdjustedStringLength + "d", FastMath.abs(termValue));
103
104 return signCharacter + integerString;
105 }
106
107 /**
108 * Convert the underlying {@link #value()} from long to int.
109 *
110 * @return The value of the term as an int
111 */
112 public int toInt() {
113 return FastMath.toIntExact(value());
114 }
115
116 /**
117 * Validate a given numerical value to ensure it is not greater than the maximum possible accuracy of this term,
118 * and that it does not contain a negative value for a positive term (when {@link #isSigned} is false).
119 *
120 * @param value long value of this term
121 */
122 protected void validateNumericValue(final long value) {
123 // Compute the number of characters excluding the sign character
124 final int n = isSigned ? length() - 1 : length();
125
126 // If the value is greater than the maximum possible value, throw an error
127 final double maxPossibleValue = FastMath.pow(10, n);
128 if (FastMath.abs(value) >= maxPossibleValue) {
129 throw new OrekitIllegalArgumentException(OrekitMessages.IIRV_VALUE_TOO_LARGE, FastMath.abs(value), maxPossibleValue);
130 }
131
132 // Throw an error if the signs don't match up
133 if (!isSigned && value < 0) {
134 throw new OrekitIllegalArgumentException(OrekitMessages.NOT_POSITIVE, value);
135 }
136 }
137 }