// 
// Decompiled by Procyon v0.6.0
// 

package io.netty.util.internal;

import java.util.List;
import java.util.ArrayList;

public final class AdaptiveCalculator
{
    private static final int INDEX_INCREMENT = 4;
    private static final int INDEX_DECREMENT = 1;
    private static final int[] SIZE_TABLE;
    private final int minIndex;
    private final int maxIndex;
    private final int minCapacity;
    private final int maxCapacity;
    private int index;
    private int nextSize;
    private boolean decreaseNow;
    
    private static int getSizeTableIndex(final int size) {
        int low = 0;
        int high = AdaptiveCalculator.SIZE_TABLE.length - 1;
        while (high >= low) {
            if (high == low) {
                return high;
            }
            final int mid = low + high >>> 1;
            final int a = AdaptiveCalculator.SIZE_TABLE[mid];
            final int b = AdaptiveCalculator.SIZE_TABLE[mid + 1];
            if (size > b) {
                low = mid + 1;
            }
            else if (size < a) {
                high = mid - 1;
            }
            else {
                if (size == a) {
                    return mid;
                }
                return mid + 1;
            }
        }
        return low;
    }
    
    public AdaptiveCalculator(final int minimum, final int initial, final int maximum) {
        ObjectUtil.checkPositive(minimum, "minimum");
        if (initial < minimum) {
            throw new IllegalArgumentException("initial: " + initial);
        }
        if (maximum < initial) {
            throw new IllegalArgumentException("maximum: " + maximum);
        }
        final int minIndex = getSizeTableIndex(minimum);
        if (AdaptiveCalculator.SIZE_TABLE[minIndex] < minimum) {
            this.minIndex = minIndex + 1;
        }
        else {
            this.minIndex = minIndex;
        }
        final int maxIndex = getSizeTableIndex(maximum);
        if (AdaptiveCalculator.SIZE_TABLE[maxIndex] > maximum) {
            this.maxIndex = maxIndex - 1;
        }
        else {
            this.maxIndex = maxIndex;
        }
        final int initialIndex = getSizeTableIndex(initial);
        if (AdaptiveCalculator.SIZE_TABLE[initialIndex] > initial) {
            this.index = initialIndex - 1;
        }
        else {
            this.index = initialIndex;
        }
        this.minCapacity = minimum;
        this.maxCapacity = maximum;
        this.nextSize = Math.max(AdaptiveCalculator.SIZE_TABLE[this.index], this.minCapacity);
    }
    
    public void record(final int size) {
        if (size <= AdaptiveCalculator.SIZE_TABLE[Math.max(0, this.index - 1)]) {
            if (this.decreaseNow) {
                this.index = Math.max(this.index - 1, this.minIndex);
                this.nextSize = Math.max(AdaptiveCalculator.SIZE_TABLE[this.index], this.minCapacity);
                this.decreaseNow = false;
            }
            else {
                this.decreaseNow = true;
            }
        }
        else if (size >= this.nextSize) {
            this.index = Math.min(this.index + 4, this.maxIndex);
            this.nextSize = Math.min(AdaptiveCalculator.SIZE_TABLE[this.index], this.maxCapacity);
            this.decreaseNow = false;
        }
    }
    
    public int nextSize() {
        return this.nextSize;
    }
    
    static {
        final List<Integer> sizeTable = new ArrayList<Integer>();
        for (int i = 16; i < 512; i += 16) {
            sizeTable.add(i);
        }
        for (int i = 512; i > 0; i <<= 1) {
            sizeTable.add(i);
        }
        SIZE_TABLE = new int[sizeTable.size()];
        for (int i = 0; i < AdaptiveCalculator.SIZE_TABLE.length; ++i) {
            AdaptiveCalculator.SIZE_TABLE[i] = sizeTable.get(i);
        }
    }
}
