// © 2020 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
package com.ibm.icu.impl.units;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.ibm.icu.impl.number.DecimalQuantity;
import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
import com.ibm.icu.number.Precision;
import com.ibm.icu.util.Measure;

/**
 * Converts from single or compound unit to single, compound or mixed units. For example, from `meter` to `foot+inch`.
 * <p>
 * DESIGN: This class uses <code>UnitsConverter</code> in order to perform the single converter (i.e. converters from
 * a single unit to another single unit). Therefore, <code>ComplexUnitsConverter</code> class contains multiple
 * instances of the <code>UnitsConverter</code> to perform the conversion.
 */
public class ComplexUnitsConverter {
    public static final BigDecimal EPSILON = BigDecimal.valueOf(Math.ulp(1.0));
    public static final BigDecimal EPSILON_MULTIPLIER = BigDecimal.valueOf(1).add(EPSILON);
    private ArrayList<UnitsConverter> unitsConverters_;
    /**
     * Individual units of mixed units, sorted big to small, with indices
     * indicating the requested output mixed unit order.
     */
    private List<MeasureUnitImpl.MeasureUnitImplWithIndex> units_;
    private MeasureUnitImpl inputUnit_;

    /**
     * Constructs <code>ComplexUnitsConverter</code> for an <code>inputUnit</code> that could be Single, Compound or
     * Mixed. In case of: 1- Single and Compound units, the conversion will not perform anything, the input will be
     * equal to the output. 2- Mixed Unit the conversion will consider the input in the biggest unit. and will convert
     * it to be spread throw the input units. For example: if input unit is "inch-and-foot", and the input is 2.5. The
     * converter will consider the input value in "foot", because foot is the biggest unit. Then, it will convert 2.5
     * feet to "inch-and-foot".
     *
     * @param targetUnit
     *            represents the input unit. could be any type. (single, compound or mixed).
     */
    public ComplexUnitsConverter(MeasureUnitImpl targetUnit, ConversionRates conversionRates) {
        this.units_ = targetUnit.extractIndividualUnitsWithIndices();
        assert (!this.units_.isEmpty());

        // Assign the biggest unit to inputUnit_.
        this.inputUnit_ = this.units_.get(0).unitImpl;
        MeasureUnitImpl.MeasureUnitImplComparator comparator = new MeasureUnitImpl.MeasureUnitImplComparator(
                conversionRates);
        for (MeasureUnitImpl.MeasureUnitImplWithIndex unitWithIndex : this.units_) {
            if (comparator.compare(unitWithIndex.unitImpl, this.inputUnit_) > 0) {
                this.inputUnit_ = unitWithIndex.unitImpl;
            }
        }

        this.init(conversionRates);
    }

    /**
     * Constructs <code>ComplexUnitsConverter</code> NOTE: - inputUnit and outputUnits must be under the same category -
     * e.g. meter to feet and inches --> all of them are length units.
     *
     * @param inputUnitIdentifier
     *              represents the source unit identifier. (should be single or compound unit).
     * @param outputUnitsIdentifier
     *              represents the output unit identifier. could be any type. (single, compound or mixed).
     */
    public ComplexUnitsConverter(String inputUnitIdentifier, String outputUnitsIdentifier) {
        this(
                MeasureUnitImpl.forIdentifier(inputUnitIdentifier),
                MeasureUnitImpl.forIdentifier(outputUnitsIdentifier),
                new ConversionRates()
        );
    }

    /**
     * Constructs <code>ComplexUnitsConverter</code> NOTE: - inputUnit and outputUnits must be under the same category -
     * e.g. meter to feet and inches --> all of them are length units.
     *
     * @param inputUnit
     *            represents the source unit. (should be single or compound unit).
     * @param outputUnits
     *            represents the output unit. could be any type. (single, compound or mixed).
     * @param conversionRates
     */
    public ComplexUnitsConverter(MeasureUnitImpl inputUnit, MeasureUnitImpl outputUnits,
            ConversionRates conversionRates) {
        this.inputUnit_ = inputUnit;
        this.units_ = outputUnits.extractIndividualUnitsWithIndices();
        assert (!this.units_.isEmpty());

        this.init(conversionRates);
    }

    /**
     * Sorts units_, which must be populated before calling this, and populates
     * unitsConverters_.
     */
    private void init(ConversionRates conversionRates) {
        // Sort the units in a descending order.
        Collections.sort(this.units_,
                Collections.reverseOrder(new MeasureUnitImpl.MeasureUnitImplWithIndexComparator(conversionRates)));

        // If the `outputUnits` is `UMEASURE_UNIT_MIXED` such as `foot+inch`. Thus means there is more than one unit
        //  and In this case we need more converters to convert from the `inputUnit` to the first unit in the
        //  `outputUnits`. Then, a converter from the first unit in the `outputUnits` to the second unit and so on.
        //      For Example:
        //          - inputUnit is `meter`
        //          - outputUnits is `foot+inch`
        //              - Therefore, we need to have two converters:
        //                      1. a converter from `meter` to `foot`
        //                      2. a converter from `foot` to `inch`
        //          - Therefore, if the input is `2 meter`:
        //              1. convert `meter` to `foot` --> 2 meter to 6.56168 feet
        //              2. convert the residual of 6.56168 feet (0.56168) to inches, which will be (6.74016
        //              inches)
        //              3. then, the final result will be (6 feet and 6.74016 inches)
        unitsConverters_ = new ArrayList<>();
        for (int i = 0, n = units_.size(); i < n; i++) {
            if (i == 0) { // first element
                unitsConverters_.add(new UnitsConverter(this.inputUnit_, units_.get(i).unitImpl, conversionRates));
            } else {
                unitsConverters_
                        .add(new UnitsConverter(units_.get(i - 1).unitImpl, units_.get(i).unitImpl, conversionRates));
            }
        }
    }

    /**
     * Returns true if the specified `quantity` of the `inputUnit`, expressed in terms of the biggest unit in the
     * MeasureUnit `outputUnit`, is greater than or equal to `limit`.
     * <p>
     * For example, if the input unit is `meter` and the target unit is `foot+inch`. Therefore, this function will
     * convert the `quantity` from `meter` to `foot`, then, it will compare the value in `foot` with the `limit`.
     */
    public boolean greaterThanOrEqual(BigDecimal quantity, BigDecimal limit) {
        assert !units_.isEmpty();

        // NOTE: First converter converts to the biggest quantity.
        return unitsConverters_.get(0).convert(quantity).multiply(EPSILON_MULTIPLIER).compareTo(limit) >= 0;
    }

    public static class ComplexConverterResult {
        public final int indexOfQuantity;
        public final List<Measure> measures;

        ComplexConverterResult(int indexOfQuantity, List<Measure> measures) {
            this.indexOfQuantity = indexOfQuantity;
            this.measures = measures;
        }
    }

    /**
     * Returns outputMeasures which is an array with the corresponding values.
     * - E.g. converting meters to feet and inches.
     * 1 meter --> 3 feet, 3.3701 inches
     * NOTE:
     * the smallest element is the only element that could have fractional values. And all
     * other elements are floored to the nearest integer
     */
    public ComplexConverterResult convert(BigDecimal quantity, Precision rounder) {
        BigInteger sign = BigInteger.ONE;
        if (quantity.compareTo(BigDecimal.ZERO) < 0) {
            quantity = quantity.abs();
            sign = sign.negate();
        }

        // For N converters:
        // - the first converter converts from the input unit to the largest
        //   unit,
        // - N-1 converters convert to bigger units for which we want integers,
        // - the Nth converter (index N-1) converts to the smallest unit, which
        //   isn't (necessarily) an integer.
        List<BigInteger> intValues = new ArrayList<>(unitsConverters_.size() - 1);
        for (int i = 0, n = unitsConverters_.size(); i < n; ++i) {
            quantity = (unitsConverters_.get(i)).convert(quantity);

            if (i < n - 1) {
                // The double type has 15 decimal digits of precision. For choosing
                // whether to use the current unit or the next smaller unit, we
                // therefore nudge up the number with which the thresholding
                // decision is made. However after the thresholding, we use the
                // original values to ensure unbiased accuracy (to the extent of
                // double's capabilities).
                BigInteger flooredQuantity = quantity.multiply(EPSILON_MULTIPLIER).setScale(0, RoundingMode.FLOOR).toBigInteger();
                intValues.add(flooredQuantity);

                // Keep the residual of the quantity.
                // For example: `3.6 feet`, keep only `0.6 feet`
                BigDecimal remainder = quantity.subtract(BigDecimal.valueOf(flooredQuantity.longValue()));
                if (remainder.compareTo(BigDecimal.ZERO) == -1) {
                    quantity = BigDecimal.ZERO;
                } else {
                    quantity = remainder;
                }
            }
        }

        quantity = applyRounder(intValues, quantity, rounder);

        // Initialize empty measures.
        List<Measure> measures = new ArrayList<>(unitsConverters_.size());
        for (int i = 0; i < unitsConverters_.size(); i++) {
            measures.add(null);
        }

        // Package values into Measure instances in measures:
        int indexOfQuantity = -1;
        for (int i = 0, n = unitsConverters_.size(); i < n; ++i) {
            if (i < n - 1) {
                Measure measure = new Measure(intValues.get(i).multiply(sign), units_.get(i).unitImpl.build());
                measures.set(units_.get(i).index, measure);
            } else {
                indexOfQuantity = units_.get(i).index;
                Measure measure =
                        new Measure(quantity.multiply(BigDecimal.valueOf(sign.longValue())),
                                units_.get(i).unitImpl.build());
                measures.set(indexOfQuantity, measure);
            }
        }

        return new ComplexConverterResult(indexOfQuantity , measures);
    }

    /**
     * Applies the rounder to the quantity (last element) and bubble up any carried value to all the intValues.
     *
     * @return the rounded quantity
     */
    private BigDecimal applyRounder(List<BigInteger> intValues, BigDecimal quantity, Precision rounder) {
        if (rounder == null) {
            return quantity;
        }

        DecimalQuantity quantityBCD = new DecimalQuantity_DualStorageBCD(quantity);
        rounder.apply(quantityBCD);
        quantity = quantityBCD.toBigDecimal();

        if (intValues.size() == 0) {
            // There is only one element, Therefore, nothing to be done
            return quantity;
        }

        // Check if there's a carry, and bubble it back up the resulting intValues.
        int lastIndex = unitsConverters_.size() - 1;
        BigDecimal carry = unitsConverters_.get(lastIndex).convertInverse(quantity).multiply(EPSILON_MULTIPLIER)
                .setScale(0, RoundingMode.FLOOR);
        if (carry.compareTo(BigDecimal.ZERO) <= 0) { // carry is not greater than zero
            return quantity;
        }
        quantity = quantity.subtract(unitsConverters_.get(lastIndex).convert(carry));
        intValues.set(lastIndex - 1, intValues.get(lastIndex - 1).add(carry.toBigInteger()));

        // We don't use the first converter: that one is for the input unit
        for (int j = lastIndex - 1; j > 0; j--) {
            carry = unitsConverters_.get(j)
                    .convertInverse(BigDecimal.valueOf(intValues.get(j).longValue()))
                    .multiply(EPSILON_MULTIPLIER)
                    .setScale(0, RoundingMode.FLOOR);
            if (carry.compareTo(BigDecimal.ZERO) <= 0) { // carry is not greater than zero
                break;
            }
            intValues.set(j, intValues.get(j).subtract(unitsConverters_.get(j).convert(carry).toBigInteger()));
            intValues.set(j - 1, intValues.get(j - 1).add(carry.toBigInteger()));
        }

        return quantity;
    }

    @Override
    public String toString() {
        return "ComplexUnitsConverter [unitsConverters_=" + unitsConverters_ + ", units_=" + units_ + "]";
    }
}
