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

package io.netty.handler.codec.http;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.CodecException;
import io.netty.channel.ChannelHandler;
import io.netty.util.ReferenceCountUtil;
import java.util.List;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;

public abstract class HttpContentDecoder extends MessageToMessageDecoder<HttpObject>
{
    static final String IDENTITY;
    protected ChannelHandlerContext ctx;
    private EmbeddedChannel decoder;
    private boolean continueResponse;
    private boolean needRead;
    private ByteBufForwarder forwarder;
    
    public HttpContentDecoder() {
        super(HttpObject.class);
        this.needRead = true;
    }
    
    @Override
    protected void decode(final ChannelHandlerContext ctx, final HttpObject msg, final List<Object> out) throws Exception {
        this.needRead = true;
        if (msg instanceof HttpResponse && ((HttpResponse)msg).status().code() == 100) {
            if (!(msg instanceof LastHttpContent)) {
                this.continueResponse = true;
            }
            this.needRead = false;
            ctx.fireChannelRead((Object)ReferenceCountUtil.retain(msg));
            return;
        }
        if (this.continueResponse) {
            if (msg instanceof LastHttpContent) {
                this.continueResponse = false;
            }
            this.needRead = false;
            ctx.fireChannelRead((Object)ReferenceCountUtil.retain(msg));
            return;
        }
        if (msg instanceof HttpMessage) {
            this.cleanup();
            final HttpMessage message = (HttpMessage)msg;
            final HttpHeaders headers = message.headers();
            String contentEncoding = headers.get(HttpHeaderNames.CONTENT_ENCODING);
            if (contentEncoding != null) {
                contentEncoding = contentEncoding.trim();
            }
            else {
                final String transferEncoding = headers.get(HttpHeaderNames.TRANSFER_ENCODING);
                if (transferEncoding != null) {
                    final int idx = transferEncoding.indexOf(44);
                    if (idx != -1) {
                        contentEncoding = transferEncoding.substring(0, idx).trim();
                    }
                    else {
                        contentEncoding = transferEncoding.trim();
                    }
                }
                else {
                    contentEncoding = HttpContentDecoder.IDENTITY;
                }
            }
            this.decoder = this.newContentDecoder(contentEncoding);
            if (this.decoder == null) {
                if (message instanceof HttpContent) {
                    ((HttpContent)message).retain();
                }
                this.needRead = false;
                ctx.fireChannelRead((Object)message);
                return;
            }
            this.decoder.pipeline().addLast(this.forwarder);
            if (headers.contains(HttpHeaderNames.CONTENT_LENGTH)) {
                headers.remove(HttpHeaderNames.CONTENT_LENGTH);
                headers.set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED);
            }
            final CharSequence targetContentEncoding = this.getTargetContentEncoding(contentEncoding);
            if (HttpHeaderValues.IDENTITY.contentEquals(targetContentEncoding)) {
                headers.remove(HttpHeaderNames.CONTENT_ENCODING);
            }
            else {
                headers.set(HttpHeaderNames.CONTENT_ENCODING, targetContentEncoding);
            }
            if (message instanceof HttpContent) {
                HttpMessage copy;
                if (message instanceof HttpRequest) {
                    final HttpRequest r = (HttpRequest)message;
                    copy = new DefaultHttpRequest(r.protocolVersion(), r.method(), r.uri());
                }
                else {
                    if (!(message instanceof HttpResponse)) {
                        throw new CodecException("Object of class " + message.getClass().getName() + " is not an HttpRequest or HttpResponse");
                    }
                    final HttpResponse r2 = (HttpResponse)message;
                    copy = new DefaultHttpResponse(r2.protocolVersion(), r2.status());
                }
                copy.headers().set(message.headers());
                copy.setDecoderResult(message.decoderResult());
                this.needRead = false;
                ctx.fireChannelRead((Object)copy);
            }
            else {
                this.needRead = false;
                ctx.fireChannelRead((Object)message);
            }
        }
        if (msg instanceof HttpContent) {
            final HttpContent c = (HttpContent)msg;
            if (this.decoder == null) {
                this.needRead = false;
                ctx.fireChannelRead((Object)c.retain());
            }
            else {
                this.decoder.writeInbound(c.content().retain());
                if (c instanceof LastHttpContent) {
                    final boolean notEmpty = this.decoder.finish();
                    this.decoder = null;
                    assert !notEmpty;
                    final LastHttpContent last = (LastHttpContent)c;
                    final HttpHeaders headers2 = last.trailingHeaders();
                    this.needRead = false;
                    if (headers2.isEmpty()) {
                        ctx.fireChannelRead((Object)LastHttpContent.EMPTY_LAST_CONTENT);
                    }
                    else {
                        ctx.fireChannelRead((Object)new ComposedLastHttpContent(headers2, DecoderResult.SUCCESS));
                    }
                }
            }
        }
    }
    
    @Override
    public void channelReadComplete(final ChannelHandlerContext ctx) throws Exception {
        final boolean needRead = this.needRead;
        this.needRead = true;
        try {
            ctx.fireChannelReadComplete();
        }
        finally {
            if (needRead && !ctx.channel().config().isAutoRead()) {
                ctx.read();
            }
        }
    }
    
    protected abstract EmbeddedChannel newContentDecoder(final String p0) throws Exception;
    
    protected String getTargetContentEncoding(final String contentEncoding) throws Exception {
        return HttpContentDecoder.IDENTITY;
    }
    
    @Override
    public void handlerRemoved(final ChannelHandlerContext ctx) throws Exception {
        this.cleanupSafely(ctx);
        super.handlerRemoved(ctx);
    }
    
    @Override
    public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
        this.cleanupSafely(ctx);
        super.channelInactive(ctx);
    }
    
    @Override
    public void handlerAdded(final ChannelHandlerContext ctx) throws Exception {
        this.ctx = ctx;
        this.forwarder = new ByteBufForwarder(ctx);
        super.handlerAdded(ctx);
    }
    
    private void cleanup() {
        if (this.decoder != null) {
            final boolean nonEmpty = this.decoder.finishAndReleaseAll();
            this.decoder = null;
            assert !nonEmpty;
        }
    }
    
    private void cleanupSafely(final ChannelHandlerContext ctx) {
        try {
            this.cleanup();
        }
        catch (final Throwable cause) {
            ctx.fireExceptionCaught(cause);
        }
    }
    
    static {
        IDENTITY = HttpHeaderValues.IDENTITY.toString();
    }
    
    private final class ByteBufForwarder extends ChannelInboundHandlerAdapter
    {
        private final ChannelHandlerContext targetCtx;
        
        ByteBufForwarder(final ChannelHandlerContext targetCtx) {
            this.targetCtx = targetCtx;
        }
        
        @Override
        public boolean isSharable() {
            return true;
        }
        
        @Override
        public void channelRead(final ChannelHandlerContext ctx, final Object msg) {
            final ByteBuf buf = (ByteBuf)msg;
            if (!buf.isReadable()) {
                buf.release();
                return;
            }
            HttpContentDecoder.this.needRead = false;
            this.targetCtx.fireChannelRead((Object)new DefaultHttpContent(buf));
        }
    }
}
