LongValuedIIRVTerm.java
/* Copyright 2024-2025 The Johns Hopkins University Applied Physics Laboratory
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.files.iirv.terms.base;
import org.hipparchus.util.FastMath;
import org.orekit.errors.OrekitIllegalArgumentException;
import org.orekit.errors.OrekitMessages;
import java.util.regex.Pattern;
/**
* Term in an IIRV Vector representing a Long (or integer) value.
*
* @author Nick LaFarge
* @since 13.0
*/
public class LongValuedIIRVTerm extends IIRVVectorTerm<Long> {
/** Space pattern. */
private static final Pattern SPACE_PATTERN = Pattern.compile(" ");
/** True if negative values are permitted, false if the value is positive. */
private final boolean isSigned;
/**
* Constructs an IIRV Vector Term represented by a long. This representation is used for any numeric terms
* in the IIRV Vector that do not contain a decimal point.
*
* @param pattern Regular expression pattern that validates the term
* @param value Value of the term, expressed as a long
* @param length LengthC of the term, measured in number of characters in the String representation
* @param isSigned True if negative values are permitted, false if the value is positive
*/
public LongValuedIIRVTerm(final String pattern, final long value, final int length, final boolean isSigned) {
super(pattern, value, length);
this.isSigned = isSigned;
validateString(toEncodedString(value));
validateNumericValue(this.value());
}
/**
* Constructs an IIRV Vector Term represented by a Long. This representation is used for any numeric terms
* in the IIRV Vector that do not contain a decimal point.
*
* @param pattern Regular expression pattern that validates the term
* @param value Value of the term, expressed as a String
* @param length Length of the term, measured in number of characters in the String representation
* @param isSigned True if negative values are permitted, false if the value is positive
*/
public LongValuedIIRVTerm(final String pattern, final String value, final int length, final boolean isSigned) {
super(pattern, LongValuedIIRVTerm.computeValueFromString(value), length);
this.isSigned = isSigned;
validateString(value);
validateNumericValue(this.value());
}
/**
* Parses a string as a long, removing any leading spaces.
*
* @param value String value of the term.
* @return the long represented by the argument
*/
public static long computeValueFromString(final String value) {
try {
// Remove spaces (for positive values)
final String integerString = SPACE_PATTERN.matcher(value).replaceAll("");
// Cast String to integer
return Long.parseLong(integerString);
} catch (NumberFormatException nfe) {
throw new OrekitIllegalArgumentException(OrekitMessages.IIRV_INVALID_TERM_VALUE, value);
}
}
/** {@inheritDoc} */
@Override
public String toEncodedString(final Long termValue) {
// Reserve one character for the sign (if applicable)
final int signAdjustedStringLength = isSigned ? length() - 1 : length();
String signCharacter = ""; // Sign character ('' for unsigned number)
if (isSigned) {
signCharacter = termValue > 0 ? " " : "-";
}
// Pad each string with zeros to reach the desired length
final String integerString = String.format("%0" + signAdjustedStringLength + "d", FastMath.abs(termValue));
return signCharacter + integerString;
}
/**
* Convert the underlying {@link #value()} from long to int.
*
* @return The value of the term as an int
*/
public int toInt() {
return FastMath.toIntExact(value());
}
/**
* Validate a given numerical value to ensure it is not greater than the maximum possible accuracy of this term,
* and that it does not contain a negative value for a positive term (when {@link #isSigned} is false).
*
* @param value long value of this term
*/
protected void validateNumericValue(final long value) {
// Compute the number of characters excluding the sign character
final int n = isSigned ? length() - 1 : length();
// If the value is greater than the maximum possible value, throw an error
final double maxPossibleValue = FastMath.pow(10, n);
if (FastMath.abs(value) >= maxPossibleValue) {
throw new OrekitIllegalArgumentException(OrekitMessages.IIRV_VALUE_TOO_LARGE, FastMath.abs(value), maxPossibleValue);
}
// Throw an error if the signs don't match up
if (!isSigned && value < 0) {
throw new OrekitIllegalArgumentException(OrekitMessages.NOT_POSITIVE, value);
}
}
}