All Downloads are FREE. Search and download functionalities are using the official Maven repository.

me.datafox.dfxengine.text.suffix.CharDigitSuffixFormatter Maven / Gradle / Ivy

The newest version!
package me.datafox.dfxengine.text.suffix;

import ch.obermuhlner.math.big.BigDecimalMath;
import lombok.Getter;
import me.datafox.dfxengine.handles.api.Handle;
import me.datafox.dfxengine.injector.api.annotation.Component;
import me.datafox.dfxengine.injector.api.annotation.Inject;
import me.datafox.dfxengine.text.api.ConfigurationKey;
import me.datafox.dfxengine.text.api.NumberSuffixFormatter;
import me.datafox.dfxengine.text.api.TextConfiguration;
import me.datafox.dfxengine.text.api.TextFactory;
import me.datafox.dfxengine.text.api.exception.TextConfigurationException;
import me.datafox.dfxengine.text.utils.TextHandles;
import me.datafox.dfxengine.text.utils.internal.TextStrings;
import me.datafox.dfxengine.utils.LogUtils;
import org.slf4j.Logger;

import java.math.BigDecimal;
import java.util.HashSet;
import java.util.Set;

/**
 * A {@link NumberSuffixFormatter} that generates an exponential suffix in an arbitrary base with an arbitrary set of
 * characters representing digits. The character set can be configured with {@link #CHARACTERS}, and {@link #INTERVAL}
 * determines how many powers of ten is required for the exponent to increase. The formatter can also be configured to
 * output a plus sign on positive exponents with {@link #EXPONENT_PLUS}.
 *
 * @author datafox
 */
@Component
public class CharDigitSuffixFormatter implements NumberSuffixFormatter {
    /**
     * 26 English alphabet in lowercase.
     */
    public static final char[] ALPHABET = new char[] {
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
    };

    /**
     * Characters to be used as digits for the exponent. The default value is {@link #ALPHABET}.
     */
    public static final ConfigurationKey CHARACTERS = ConfigurationKey.of(ALPHABET);

    /**
     * Interval for formatted exponents. The default value is {@code 3}.
     */
    public static final ConfigurationKey INTERVAL = ConfigurationKey.of(3);

    /**
     * If {@code true}, will output a plus sign on positive exponents. The default value is {@code false}.
     */
    public static final ConfigurationKey EXPONENT_PLUS = ConfigurationKey.of(false);

    private final Logger logger;
    @Getter
    private final Handle handle;

    /**
     * @param logger {@link Logger} for this formatter
     * @param handles {@link TextHandles} to be used for this formatter's {@link Handle}
     */
    @Inject
    public CharDigitSuffixFormatter(Logger logger, TextHandles handles) {
        this.logger = logger;
        handle = handles.getCharDigitSuffixFormatter();
    }

    /**
     * @param number {@inheritDoc}
     * @param factory {@inheritDoc}
     * @param configuration {@inheritDoc}
     * @return {@inheritDoc}
     *
     * @throws TextConfigurationException {@inheritDoc}
     */
    @Override
    public Output format(BigDecimal number, TextFactory factory, TextConfiguration configuration) {
        if(number == null) {
            number = BigDecimal.ZERO;
        }
        int interval = configuration.get(INTERVAL);
        char[] characters = configuration.get(CHARACTERS);
        validateConfiguration(interval, characters);
        int shift = 0;
        int exponent = BigDecimalMath.exponent(number);
        boolean negativeExponent = exponent < 0;
        int index = exponent;
        if(interval != 1) {
            shift = Math.floorMod(exponent, interval);
            index = Math.floorDiv(exponent, interval);
        }
        index = Math.abs(index);
        BigDecimal mantissa = BigDecimalMath.mantissa(number);
        if(shift != 0) {
            mantissa = mantissa.movePointRight(shift);
        }
        if(index == 0) {
            return new Output(mantissa, "");
        }
        StringBuilder sb = new StringBuilder();
        while(true) {
            sb.insert(0, characters[(index - 1) % characters.length]);
            if(index <= characters.length) {
                break;
            }
            index = (index - 1) / characters.length;
        }
        if(negativeExponent) {
            sb.insert(0, '-');
        } else if(configuration.get(EXPONENT_PLUS)) {
            sb.insert(0, '+');
        }
        return new Output(mantissa, sb.toString());
    }

    /**
     * @return {@inheritDoc}. Always returns {@code true}
     */
    @Override
    public boolean isInfinite() {
        return true;
    }

    private void validateConfiguration(int interval, char[] characters) {
        if(interval <= 0) {
            throw LogUtils.logExceptionAndGet(logger,
                    TextStrings.cdsfInvalidInterval(interval),
                    TextConfigurationException::new);
        }
        if(characters.length == 0) {
            throw LogUtils.logExceptionAndGet(logger,
                    TextStrings.CDSF_EMPTY_CHAR_ARRAY,
                    TextConfigurationException::new);
        }
        Set visited = new HashSet<>();
        for(char c : characters) {
            if(!visited.add(c)) {
                logger.warn(TextStrings.CDSF_NOT_DISTINCT_CHAR_ARRAY);
                break;
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy