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

package io.netty.handler.codec.http3;

import java.util.Arrays;

final class QpackDecoderDynamicTable
{
    private static final QpackException GET_ENTRY_ILLEGAL_INDEX_VALUE;
    private static final QpackException HEADER_TOO_LARGE;
    private QpackHeaderField[] fields;
    private int head;
    private int tail;
    private long size;
    private long capacity;
    private int insertCount;
    
    QpackDecoderDynamicTable() {
        this.capacity = -1L;
    }
    
    int length() {
        return (this.head < this.tail) ? (this.fields.length - this.tail + this.head) : (this.head - this.tail);
    }
    
    long size() {
        return this.size;
    }
    
    int insertCount() {
        return this.insertCount;
    }
    
    QpackHeaderField getEntry(final int index) throws QpackException {
        if (index < 0 || this.fields == null || index >= this.fields.length) {
            throw QpackDecoderDynamicTable.GET_ENTRY_ILLEGAL_INDEX_VALUE;
        }
        final QpackHeaderField entry = this.fields[index];
        if (entry == null) {
            throw QpackDecoderDynamicTable.GET_ENTRY_ILLEGAL_INDEX_VALUE;
        }
        return entry;
    }
    
    QpackHeaderField getEntryRelativeEncodedField(final int index) throws QpackException {
        return this.getEntry(this.moduloIndex(index));
    }
    
    QpackHeaderField getEntryRelativeEncoderInstructions(final int index) throws QpackException {
        return this.getEntry((index > this.tail) ? (this.fields.length - index + this.tail) : (this.tail - index));
    }
    
    void add(final QpackHeaderField header) throws QpackException {
        final long headerSize = header.size();
        if (headerSize > this.capacity) {
            throw QpackDecoderDynamicTable.HEADER_TOO_LARGE;
        }
        while (this.capacity - this.size < headerSize) {
            this.remove();
        }
        ++this.insertCount;
        this.fields[this.getAndIncrementHead()] = header;
        this.size += headerSize;
    }
    
    private void remove() {
        final QpackHeaderField removed = this.fields[this.tail];
        if (removed == null) {
            return;
        }
        this.size -= removed.size();
        this.fields[this.getAndIncrementTail()] = null;
    }
    
    void clear() {
        if (this.fields != null) {
            Arrays.fill(this.fields, null);
        }
        this.head = 0;
        this.tail = 0;
        this.size = 0L;
    }
    
    void setCapacity(final long capacity) throws QpackException {
        if (capacity < 0L || capacity > 4294967295L) {
            throw new IllegalArgumentException("capacity is invalid: " + capacity);
        }
        if (this.capacity == capacity) {
            return;
        }
        this.capacity = capacity;
        if (capacity == 0L) {
            this.clear();
        }
        else {
            while (this.size > capacity) {
                this.remove();
            }
        }
        final int maxEntries = QpackUtil.toIntOrThrow(2L * Math.floorDiv(capacity, 32L));
        if (this.fields != null && this.fields.length == maxEntries) {
            return;
        }
        final QpackHeaderField[] tmp = new QpackHeaderField[maxEntries];
        final int len = this.length();
        if (this.fields != null && this.tail != this.head) {
            if (this.head > this.tail) {
                System.arraycopy(this.fields, this.tail, tmp, 0, this.head - this.tail);
            }
            else {
                System.arraycopy(this.fields, 0, tmp, 0, this.head);
                System.arraycopy(this.fields, this.tail, tmp, this.head, this.fields.length - this.tail);
            }
        }
        this.tail = 0;
        this.head = this.tail + len;
        this.fields = tmp;
    }
    
    private int getAndIncrementHead() {
        final int val = this.head;
        this.head = this.safeIncrementIndex(val);
        return val;
    }
    
    private int getAndIncrementTail() {
        final int val = this.tail;
        this.tail = this.safeIncrementIndex(val);
        return val;
    }
    
    private int safeIncrementIndex(int index) {
        return ++index % this.fields.length;
    }
    
    private int moduloIndex(final int index) {
        return (this.fields == null) ? index : (index % this.fields.length);
    }
    
    static {
        GET_ENTRY_ILLEGAL_INDEX_VALUE = QpackException.newStatic(QpackDecoderDynamicTable.class, "getEntry(...)", "QPACK - illegal decoder dynamic table index value");
        HEADER_TOO_LARGE = QpackException.newStatic(QpackDecoderDynamicTable.class, "add(...)", "QPACK - header entry too large.");
    }
}
