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

package io.netty.handler.codec.quic;

import io.netty.channel.ChannelHandler;
import io.netty.util.internal.ObjectUtil;
import java.util.concurrent.TimeUnit;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Function;

public abstract class QuicCodecBuilder<B extends QuicCodecBuilder<B>>
{
    private final boolean server;
    private Boolean grease;
    private Long maxIdleTimeout;
    private Long maxRecvUdpPayloadSize;
    private Long maxSendUdpPayloadSize;
    private Long initialMaxData;
    private Long initialMaxStreamDataBidiLocal;
    private Long initialMaxStreamDataBidiRemote;
    private Long initialMaxStreamDataUni;
    private Long initialMaxStreamsBidi;
    private Long initialMaxStreamsUni;
    private Long ackDelayExponent;
    private Long maxAckDelay;
    private Boolean disableActiveMigration;
    private Boolean enableHystart;
    private Boolean discoverPmtu;
    private QuicCongestionControlAlgorithm congestionControlAlgorithm;
    private Integer initialCongestionWindowPackets;
    private int localConnIdLength;
    private Function<QuicChannel, ? extends QuicSslEngine> sslEngineProvider;
    private FlushStrategy flushStrategy;
    private Integer recvQueueLen;
    private Integer sendQueueLen;
    private Long activeConnectionIdLimit;
    private byte[] statelessResetToken;
    private Executor sslTaskExecutor;
    int version;
    
    QuicCodecBuilder(final boolean server) {
        this.flushStrategy = FlushStrategy.DEFAULT;
        Quic.ensureAvailability();
        this.version = Quiche.QUICHE_PROTOCOL_VERSION;
        this.localConnIdLength = Quiche.QUICHE_MAX_CONN_ID_LEN;
        this.server = server;
    }
    
    QuicCodecBuilder(final QuicCodecBuilder<B> builder) {
        this.flushStrategy = FlushStrategy.DEFAULT;
        Quic.ensureAvailability();
        this.server = builder.server;
        this.grease = builder.grease;
        this.maxIdleTimeout = builder.maxIdleTimeout;
        this.maxRecvUdpPayloadSize = builder.maxRecvUdpPayloadSize;
        this.maxSendUdpPayloadSize = builder.maxSendUdpPayloadSize;
        this.initialMaxData = builder.initialMaxData;
        this.initialMaxStreamDataBidiLocal = builder.initialMaxStreamDataBidiLocal;
        this.initialMaxStreamDataBidiRemote = builder.initialMaxStreamDataBidiRemote;
        this.initialMaxStreamDataUni = builder.initialMaxStreamDataUni;
        this.initialMaxStreamsBidi = builder.initialMaxStreamsBidi;
        this.initialMaxStreamsUni = builder.initialMaxStreamsUni;
        this.ackDelayExponent = builder.ackDelayExponent;
        this.maxAckDelay = builder.maxAckDelay;
        this.disableActiveMigration = builder.disableActiveMigration;
        this.enableHystart = builder.enableHystart;
        this.discoverPmtu = builder.discoverPmtu;
        this.congestionControlAlgorithm = builder.congestionControlAlgorithm;
        this.initialCongestionWindowPackets = builder.initialCongestionWindowPackets;
        this.localConnIdLength = builder.localConnIdLength;
        this.sslEngineProvider = builder.sslEngineProvider;
        this.flushStrategy = builder.flushStrategy;
        this.recvQueueLen = builder.recvQueueLen;
        this.sendQueueLen = builder.sendQueueLen;
        this.activeConnectionIdLimit = builder.activeConnectionIdLimit;
        this.statelessResetToken = builder.statelessResetToken;
        this.sslTaskExecutor = builder.sslTaskExecutor;
        this.version = builder.version;
    }
    
    protected final B self() {
        return (B)this;
    }
    
    public final B flushStrategy(final FlushStrategy flushStrategy) {
        this.flushStrategy = Objects.requireNonNull(flushStrategy, "flushStrategy");
        return this.self();
    }
    
    public final B congestionControlAlgorithm(final QuicCongestionControlAlgorithm congestionControlAlgorithm) {
        this.congestionControlAlgorithm = congestionControlAlgorithm;
        return this.self();
    }
    
    public final B initialCongestionWindowPackets(final int numPackets) {
        this.initialCongestionWindowPackets = numPackets;
        return this.self();
    }
    
    public final B grease(final boolean enable) {
        this.grease = enable;
        return this.self();
    }
    
    public final B maxIdleTimeout(final long amount, final TimeUnit unit) {
        this.maxIdleTimeout = unit.toMillis(ObjectUtil.checkPositiveOrZero(amount, "amount"));
        return this.self();
    }
    
    public final B maxSendUdpPayloadSize(final long size) {
        this.maxSendUdpPayloadSize = ObjectUtil.checkPositiveOrZero(size, "value");
        return this.self();
    }
    
    public final B maxRecvUdpPayloadSize(final long size) {
        this.maxRecvUdpPayloadSize = ObjectUtil.checkPositiveOrZero(size, "value");
        return this.self();
    }
    
    public final B initialMaxData(final long value) {
        this.initialMaxData = ObjectUtil.checkPositiveOrZero(value, "value");
        return this.self();
    }
    
    public final B initialMaxStreamDataBidirectionalLocal(final long value) {
        this.initialMaxStreamDataBidiLocal = ObjectUtil.checkPositiveOrZero(value, "value");
        return this.self();
    }
    
    public final B initialMaxStreamDataBidirectionalRemote(final long value) {
        this.initialMaxStreamDataBidiRemote = ObjectUtil.checkPositiveOrZero(value, "value");
        return this.self();
    }
    
    public final B initialMaxStreamDataUnidirectional(final long value) {
        this.initialMaxStreamDataUni = ObjectUtil.checkPositiveOrZero(value, "value");
        return this.self();
    }
    
    public final B initialMaxStreamsBidirectional(final long value) {
        this.initialMaxStreamsBidi = ObjectUtil.checkPositiveOrZero(value, "value");
        return this.self();
    }
    
    public final B initialMaxStreamsUnidirectional(final long value) {
        this.initialMaxStreamsUni = ObjectUtil.checkPositiveOrZero(value, "value");
        return this.self();
    }
    
    public final B ackDelayExponent(final long value) {
        this.ackDelayExponent = ObjectUtil.checkPositiveOrZero(value, "value");
        return this.self();
    }
    
    public final B maxAckDelay(final long amount, final TimeUnit unit) {
        this.maxAckDelay = unit.toMillis(ObjectUtil.checkPositiveOrZero(amount, "amount"));
        return this.self();
    }
    
    public final B activeMigration(final boolean enable) {
        this.disableActiveMigration = !enable;
        return this.self();
    }
    
    public final B hystart(final boolean enable) {
        this.enableHystart = enable;
        return this.self();
    }
    
    public final B discoverPmtu(final boolean enable) {
        this.discoverPmtu = enable;
        return this.self();
    }
    
    public final B localConnectionIdLength(final int value) {
        this.localConnIdLength = ObjectUtil.checkInRange(value, 0, Quiche.QUICHE_MAX_CONN_ID_LEN, "value");
        return this.self();
    }
    
    public final B version(final int version) {
        this.version = version;
        return this.self();
    }
    
    public final B datagram(final int recvQueueLen, final int sendQueueLen) {
        ObjectUtil.checkPositive(recvQueueLen, "recvQueueLen");
        ObjectUtil.checkPositive(sendQueueLen, "sendQueueLen");
        this.recvQueueLen = recvQueueLen;
        this.sendQueueLen = sendQueueLen;
        return this.self();
    }
    
    public final B sslContext(final QuicSslContext sslContext) {
        if (this.server != sslContext.isServer()) {
            throw new IllegalArgumentException("QuicSslContext.isServer() " + sslContext.isServer() + " isn't supported by this builder");
        }
        return this.sslEngineProvider(q -> sslContext.newEngine(q.alloc()));
    }
    
    public final B sslEngineProvider(final Function<QuicChannel, ? extends QuicSslEngine> sslEngineProvider) {
        this.sslEngineProvider = sslEngineProvider;
        return this.self();
    }
    
    public final B sslTaskExecutor(final Executor sslTaskExecutor) {
        this.sslTaskExecutor = sslTaskExecutor;
        return this.self();
    }
    
    public final B activeConnectionIdLimit(final long limit) {
        ObjectUtil.checkPositive(limit, "limit");
        this.activeConnectionIdLimit = limit;
        return this.self();
    }
    
    public final B statelessResetToken(final byte[] token) {
        if (token.length != 16) {
            throw new IllegalArgumentException("token must be 16 bytes but was " + token.length);
        }
        this.statelessResetToken = token.clone();
        return this.self();
    }
    
    private QuicheConfig createConfig() {
        return new QuicheConfig(this.version, this.grease, this.maxIdleTimeout, this.maxSendUdpPayloadSize, this.maxRecvUdpPayloadSize, this.initialMaxData, this.initialMaxStreamDataBidiLocal, this.initialMaxStreamDataBidiRemote, this.initialMaxStreamDataUni, this.initialMaxStreamsBidi, this.initialMaxStreamsUni, this.ackDelayExponent, this.maxAckDelay, this.disableActiveMigration, this.enableHystart, this.discoverPmtu, this.congestionControlAlgorithm, this.initialCongestionWindowPackets, this.recvQueueLen, this.sendQueueLen, this.activeConnectionIdLimit, this.statelessResetToken);
    }
    
    protected void validate() {
        if (this.sslEngineProvider == null) {
            throw new IllegalStateException("sslEngineProvider can't be null");
        }
    }
    
    public final ChannelHandler build() {
        this.validate();
        final QuicheConfig config = this.createConfig();
        try {
            return this.build(config, this.sslEngineProvider, this.sslTaskExecutor, this.localConnIdLength, this.flushStrategy);
        }
        catch (final Throwable cause) {
            config.free();
            throw cause;
        }
    }
    
    public abstract B clone();
    
    abstract ChannelHandler build(final QuicheConfig p0, final Function<QuicChannel, ? extends QuicSslEngine> p1, final Executor p2, final int p3, final FlushStrategy p4);
}
