package net.ripe.commons.ip;

import static net.ripe.commons.ip.RangeUtils.checkRange;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import com.google.common.base.Optional;

public final class PrefixUtils {

    private PrefixUtils() {
    }

    public static <C extends AbstractIp<C, R>, R extends AbstractIpRange<C, R>>
    boolean isLegalPrefix(AbstractIpRange<C, R> range) {
        int prefixLength = range.start().getCommonPrefixLength(range.end());
        C lowerBoundForPrefix = range.start().lowerBoundForPrefix(prefixLength);
        C upperBoundForPrefix = range.end().upperBoundForPrefix(prefixLength);
        return range.start().equals(lowerBoundForPrefix) && range.end().equals(upperBoundForPrefix);
    }

    public static <C extends AbstractIp<C, R>, R extends AbstractIpRange<C, R>>
    int getPrefixLength(AbstractIpRange<C, R> range) {
        Validate.isTrue(isLegalPrefix(range), range.toStringInRangeNotation() + " is not a legal prefix, cannot get prefix length!");
        return range.start().getCommonPrefixLength(range.end());
    }

    public static <C extends AbstractIp<C, R>, R extends AbstractIpRange<C, R>>
    Optional<R> findMinimumPrefixForPrefixLength(R range, int prefixLength) {
        checkRange(prefixLength, 0, range.start().bitSize());
        return findPrefixForPrefixLength(range, prefixLength, SizeComparator.<C, R>getInstance());
    }

    public static <C extends AbstractIp<C, R>, R extends AbstractIpRange<C, R>>
    Optional<R> findMaximumPrefixForPrefixLength(R range, int prefixLength) {
        checkRange(prefixLength, 0, range.start().bitSize());
        return findPrefixForPrefixLength(range, prefixLength, Collections.reverseOrder(SizeComparator.<C, R>getInstance()));
    }

    private static <C extends AbstractIp<C, R>, R extends AbstractIpRange<C, R>>
    Optional<R> findPrefixForPrefixLength(R range, int prefixLength, Comparator<? super R> comparator) {
        List<R> prefixes = range.splitToPrefixes();
        Collections.sort(prefixes, comparator);
        for (R prefix : prefixes) {
            if (prefixLength >= PrefixUtils.getPrefixLength(prefix)) {
                return Optional.of(prefix);
            }
        }
        return Optional.absent();
    }

}

@@ -23,16 +23,57 @@
 ns.ip;%0A%0A
+import static java.math.BigInteger.ZERO;%0A
 import s
@@ -121,16 +121,45 @@
 kRange;%0A
+import java.math.BigInteger;%0A
 import j
@@ -2345,10 +2345,594 @@
 %0A    %7D%0A%0A
+    // TODO(yg): generify and move to AbstractIp%0A    public static int findMaxPrefixLengthForAddress(Ipv6 address) %7B%0A        return getMaxValidPrefix(address.value());%0A    %7D%0A%0A    private static int getMaxValidPrefix(BigInteger number) %7B%0A        int powerOfTwo = 0;%0A        int maxPowerOfTwo = powerOfTwo;%0A%0A        while (powerOfTwo %3C= Ipv6.NUMBER_OF_BITS && number.divideAndRemainder(BigInteger.ONE.shiftLeft(powerOfTwo))%5B1%5D.compareTo(ZERO) == 0) %7B%0A            maxPowerOfTwo = powerOfTwo;%0A            powerOfTwo++;%0A        %7D%0A        return Ipv6.NUMBER_OF_BITS - maxPowerOfTwo;%0A    %7D%0A%0A
 %7D%0A

Put back findMaxPrefixLengthForAddress() to make RSNG compile.