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

package io.netty.handler.codec.http3;

import io.netty.util.AsciiString;
import io.netty.channel.socket.ChannelInputShutdownEvent;
import io.netty.handler.codec.quic.QuicStreamChannel;
import java.util.List;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.internal.ObjectUtil;
import org.jetbrains.annotations.Nullable;
import io.netty.handler.codec.ByteToMessageDecoder;

final class QpackEncoderHandler extends ByteToMessageDecoder
{
    private final QpackHuffmanDecoder huffmanDecoder;
    private final QpackDecoder qpackDecoder;
    private boolean discard;
    
    QpackEncoderHandler(@Nullable final Long maxTableCapacity, final QpackDecoder qpackDecoder) {
        ObjectUtil.checkInRange((maxTableCapacity == null) ? 0L : ((long)maxTableCapacity), 0L, 4294967295L, "maxTableCapacity");
        this.huffmanDecoder = new QpackHuffmanDecoder();
        this.qpackDecoder = qpackDecoder;
    }
    
    @Override
    protected void decode(final ChannelHandlerContext ctx, final ByteBuf in, final List<Object> __) throws Exception {
        if (!in.isReadable()) {
            return;
        }
        if (this.discard) {
            in.skipBytes(in.readableBytes());
            return;
        }
        final byte b = in.getByte(in.readerIndex());
        if ((b & 0xE0) == 0x20) {
            final long capacity = QpackUtil.decodePrefixedInteger(in, 5);
            if (capacity < 0L) {
                return;
            }
            try {
                this.qpackDecoder.setDynamicTableCapacity(capacity);
            }
            catch (final QpackException e) {
                this.handleDecodeFailure(ctx, e, "setDynamicTableCapacity failed.");
            }
        }
        else {
            final QpackAttributes qpackAttributes = Http3.getQpackAttributes(ctx.channel().parent());
            assert qpackAttributes != null;
            if (!qpackAttributes.dynamicTableDisabled() && !qpackAttributes.decoderStreamAvailable()) {
                return;
            }
            final QuicStreamChannel decoderStream = qpackAttributes.decoderStream();
            if ((b & 0x80) == 0x80) {
                final int readerIndex = in.readerIndex();
                final boolean isStaticTableIndex = QpackUtil.firstByteEquals(in, (byte)(-64));
                final int nameIdx = QpackUtil.decodePrefixedIntegerAsInt(in, 6);
                if (nameIdx < 0) {
                    return;
                }
                final CharSequence value = this.decodeLiteralValue(in);
                if (value == null) {
                    in.readerIndex(readerIndex);
                    return;
                }
                try {
                    this.qpackDecoder.insertWithNameReference(decoderStream, isStaticTableIndex, nameIdx, value);
                }
                catch (final QpackException e2) {
                    this.handleDecodeFailure(ctx, e2, "insertWithNameReference failed.");
                }
            }
            else if ((b & 0xC0) == 0x40) {
                final int readerIndex = in.readerIndex();
                final boolean nameHuffEncoded = QpackUtil.firstByteEquals(in, (byte)96);
                final int nameLength = QpackUtil.decodePrefixedIntegerAsInt(in, 5);
                if (nameLength < 0) {
                    in.readerIndex(readerIndex);
                    return;
                }
                if (in.readableBytes() < nameLength) {
                    in.readerIndex(readerIndex);
                    return;
                }
                final CharSequence name = this.decodeStringLiteral(in, nameHuffEncoded, nameLength);
                final CharSequence value2 = this.decodeLiteralValue(in);
                if (value2 == null) {
                    in.readerIndex(readerIndex);
                    return;
                }
                try {
                    this.qpackDecoder.insertLiteral(decoderStream, name, value2);
                }
                catch (final QpackException e3) {
                    this.handleDecodeFailure(ctx, e3, "insertLiteral failed.");
                }
            }
            else {
                if ((b & 0xE0) != 0x0) {
                    this.discard = true;
                    Http3CodecUtils.connectionError(ctx, Http3ErrorCode.QPACK_ENCODER_STREAM_ERROR, "Unknown encoder instruction '" + b + "'.", false);
                    return;
                }
                final int readerIndex = in.readerIndex();
                final int index = QpackUtil.decodePrefixedIntegerAsInt(in, 5);
                if (index < 0) {
                    in.readerIndex(readerIndex);
                    return;
                }
                try {
                    this.qpackDecoder.duplicate(decoderStream, index);
                }
                catch (final QpackException e4) {
                    this.handleDecodeFailure(ctx, e4, "duplicate failed.");
                }
            }
        }
    }
    
    @Override
    public void channelReadComplete(final ChannelHandlerContext ctx) {
        ctx.fireChannelReadComplete();
        Http3CodecUtils.readIfNoAutoRead(ctx);
    }
    
    @Override
    public void userEventTriggered(final ChannelHandlerContext ctx, final Object evt) {
        if (evt instanceof ChannelInputShutdownEvent) {
            Http3CodecUtils.criticalStreamClosed(ctx);
        }
        ctx.fireUserEventTriggered(evt);
    }
    
    @Override
    public void channelInactive(final ChannelHandlerContext ctx) {
        Http3CodecUtils.criticalStreamClosed(ctx);
        ctx.fireChannelInactive();
    }
    
    private void handleDecodeFailure(final ChannelHandlerContext ctx, final QpackException cause, final String message) {
        this.discard = true;
        Http3CodecUtils.connectionError(ctx, new Http3Exception(Http3ErrorCode.QPACK_ENCODER_STREAM_ERROR, message, cause), true);
    }
    
    @Nullable
    private CharSequence decodeLiteralValue(final ByteBuf in) throws QpackException {
        final boolean valueHuffEncoded = QpackUtil.firstByteEquals(in, (byte)(-128));
        final int valueLength = QpackUtil.decodePrefixedIntegerAsInt(in, 7);
        if (valueLength < 0 || in.readableBytes() < valueLength) {
            return null;
        }
        return this.decodeStringLiteral(in, valueHuffEncoded, valueLength);
    }
    
    private CharSequence decodeStringLiteral(final ByteBuf in, final boolean huffmanEncoded, final int length) throws QpackException {
        if (huffmanEncoded) {
            return this.huffmanDecoder.decode(in, length);
        }
        final byte[] buf = new byte[length];
        in.readBytes(buf);
        return new AsciiString(buf, false);
    }
}
