LongValuedIIRVTerm.java

  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. import org.hipparchus.util.FastMath;
  19. import org.orekit.errors.OrekitIllegalArgumentException;
  20. import org.orekit.errors.OrekitMessages;

  21. import java.util.regex.Pattern;

  22. /**
  23.  * Term in an IIRV Vector representing a Long (or integer) value.
  24.  *
  25.  * @author Nick LaFarge
  26.  * @since 13.0
  27.  */
  28. public class LongValuedIIRVTerm extends IIRVVectorTerm<Long> {

  29.     /** Space pattern. */
  30.     private static final Pattern SPACE_PATTERN = Pattern.compile(" ");

  31.     /** True if negative values are permitted, false if the value is positive. */
  32.     private final boolean isSigned;

  33.     /**
  34.      * Constructs an IIRV Vector Term represented by a long. This representation is used for any numeric terms
  35.      * in the IIRV Vector that do not contain a decimal point.
  36.      *
  37.      * @param pattern  Regular expression pattern that validates the term
  38.      * @param value    Value of the term, expressed as a long
  39.      * @param length   LengthC of the term, measured in number of characters in the String representation
  40.      * @param isSigned True if negative values are permitted, false if the value is positive
  41.      */
  42.     public LongValuedIIRVTerm(final String pattern, final long value, final int length, final boolean isSigned) {
  43.         super(pattern, value, length);
  44.         this.isSigned = isSigned;
  45.         validateString(toEncodedString(value));
  46.         validateNumericValue(this.value());
  47.     }

  48.     /**
  49.      * Constructs an IIRV Vector Term represented by a Long. This representation is used for any numeric terms
  50.      * in the IIRV Vector that do not contain a decimal point.
  51.      *
  52.      * @param pattern  Regular expression pattern that validates the term
  53.      * @param value    Value of the term, expressed as a String
  54.      * @param length   Length of the term, measured in number of characters in the String representation
  55.      * @param isSigned True if negative values are permitted, false if the value is positive
  56.      */
  57.     public LongValuedIIRVTerm(final String pattern, final String value, final int length, final boolean isSigned) {
  58.         super(pattern, LongValuedIIRVTerm.computeValueFromString(value), length);
  59.         this.isSigned = isSigned;
  60.         validateString(value);
  61.         validateNumericValue(this.value());
  62.     }

  63.     /**
  64.      * Parses a string as a long, removing any leading spaces.
  65.      *
  66.      * @param value String value of the term.
  67.      * @return the long represented by the argument
  68.      */
  69.     public static long computeValueFromString(final String value) {
  70.         try {
  71.             // Remove spaces (for positive values)
  72.             final String integerString = SPACE_PATTERN.matcher(value).replaceAll("");

  73.             // Cast String to integer
  74.             return Long.parseLong(integerString);
  75.         } catch (NumberFormatException nfe) {
  76.             throw new OrekitIllegalArgumentException(OrekitMessages.IIRV_INVALID_TERM_VALUE, value);
  77.         }
  78.     }

  79.     /** {@inheritDoc} */
  80.     @Override
  81.     public String toEncodedString(final Long termValue) {

  82.         // Reserve one character for the sign (if applicable)
  83.         final int signAdjustedStringLength = isSigned ? length() - 1 : length();

  84.         String signCharacter = "";  // Sign character ('' for unsigned number)
  85.         if (isSigned) {
  86.             signCharacter = termValue > 0 ? " " : "-";
  87.         }

  88.         // Pad each string with zeros to reach the desired length
  89.         final String integerString = String.format("%0" + signAdjustedStringLength + "d", FastMath.abs(termValue));

  90.         return signCharacter + integerString;
  91.     }

  92.     /**
  93.      * Convert the underlying {@link #value()} from long to int.
  94.      *
  95.      * @return The value of the term as an int
  96.      */
  97.     public int toInt() {
  98.         return FastMath.toIntExact(value());
  99.     }

  100.     /**
  101.      * Validate a given numerical value to ensure it is not greater than the maximum possible accuracy of this term,
  102.      * and that it does not contain a negative value for a positive term (when {@link #isSigned} is false).
  103.      *
  104.      * @param value long value of this term
  105.      */
  106.     protected void validateNumericValue(final long value) {
  107.         // Compute the number of characters excluding the sign character
  108.         final int n = isSigned ? length() - 1 : length();

  109.         // If the value is greater than the maximum possible value, throw an error
  110.         final double maxPossibleValue = FastMath.pow(10, n);
  111.         if (FastMath.abs(value) >= maxPossibleValue) {
  112.             throw new OrekitIllegalArgumentException(OrekitMessages.IIRV_VALUE_TOO_LARGE, FastMath.abs(value), maxPossibleValue);
  113.         }

  114.         // Throw an error if the signs don't match up
  115.         if (!isSigned && value < 0) {
  116.             throw new OrekitIllegalArgumentException(OrekitMessages.NOT_POSITIVE, value);
  117.         }
  118.     }
  119. }