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

package io.netty.buffer;

import io.netty.util.ReferenceCounted;
import java.nio.ByteOrder;
import io.netty.util.IllegalReferenceCountException;
import io.netty.util.internal.ThrowableUtil;
import io.netty.util.internal.ObjectUtil;
import io.netty.util.ResourceLeakTracker;

class SimpleLeakAwareByteBuf extends WrappedByteBuf
{
    private final ByteBuf trackedByteBuf;
    final ResourceLeakTracker<ByteBuf> leak;
    
    SimpleLeakAwareByteBuf(final ByteBuf wrapped, final ByteBuf trackedByteBuf, final ResourceLeakTracker<ByteBuf> leak) {
        super(wrapped);
        this.trackedByteBuf = ObjectUtil.checkNotNull(trackedByteBuf, "trackedByteBuf");
        this.leak = ObjectUtil.checkNotNull(leak, "leak");
    }
    
    SimpleLeakAwareByteBuf(final ByteBuf wrapped, final ResourceLeakTracker<ByteBuf> leak) {
        this(wrapped, wrapped, leak);
    }
    
    @Override
    public ByteBuf slice() {
        return this.newSharedLeakAwareByteBuf(super.slice());
    }
    
    @Override
    public ByteBuf retainedSlice() {
        try {
            return this.unwrappedDerived(super.retainedSlice());
        }
        catch (final IllegalReferenceCountException irce) {
            ThrowableUtil.addSuppressed(irce, this.leak.getCloseStackTraceIfAny());
            throw irce;
        }
    }
    
    @Override
    public ByteBuf retainedSlice(final int index, final int length) {
        try {
            return this.unwrappedDerived(super.retainedSlice(index, length));
        }
        catch (final IllegalReferenceCountException irce) {
            ThrowableUtil.addSuppressed(irce, this.leak.getCloseStackTraceIfAny());
            throw irce;
        }
    }
    
    @Override
    public ByteBuf retainedDuplicate() {
        try {
            return this.unwrappedDerived(super.retainedDuplicate());
        }
        catch (final IllegalReferenceCountException irce) {
            ThrowableUtil.addSuppressed(irce, this.leak.getCloseStackTraceIfAny());
            throw irce;
        }
    }
    
    @Override
    public ByteBuf readRetainedSlice(final int length) {
        try {
            return this.unwrappedDerived(super.readRetainedSlice(length));
        }
        catch (final IllegalReferenceCountException irce) {
            ThrowableUtil.addSuppressed(irce, this.leak.getCloseStackTraceIfAny());
            throw irce;
        }
    }
    
    @Override
    public ByteBuf slice(final int index, final int length) {
        return this.newSharedLeakAwareByteBuf(super.slice(index, length));
    }
    
    @Override
    public ByteBuf duplicate() {
        return this.newSharedLeakAwareByteBuf(super.duplicate());
    }
    
    @Override
    public ByteBuf readSlice(final int length) {
        return this.newSharedLeakAwareByteBuf(super.readSlice(length));
    }
    
    @Override
    public ByteBuf asReadOnly() {
        return this.newSharedLeakAwareByteBuf(super.asReadOnly());
    }
    
    @Override
    public ByteBuf touch() {
        return this;
    }
    
    @Override
    public ByteBuf touch(final Object hint) {
        return this;
    }
    
    @Override
    public ByteBuf retain() {
        try {
            return super.retain();
        }
        catch (final IllegalReferenceCountException irce) {
            ThrowableUtil.addSuppressed(irce, this.leak.getCloseStackTraceIfAny());
            throw irce;
        }
    }
    
    @Override
    public ByteBuf retain(final int increment) {
        try {
            return super.retain(increment);
        }
        catch (final IllegalReferenceCountException irce) {
            ThrowableUtil.addSuppressed(irce, this.leak.getCloseStackTraceIfAny());
            throw irce;
        }
    }
    
    @Override
    public boolean release() {
        try {
            if (super.release()) {
                this.closeLeak();
                return true;
            }
            return false;
        }
        catch (final IllegalReferenceCountException irce) {
            ThrowableUtil.addSuppressed(irce, this.leak.getCloseStackTraceIfAny());
            throw irce;
        }
    }
    
    @Override
    public boolean release(final int decrement) {
        try {
            if (super.release(decrement)) {
                this.closeLeak();
                return true;
            }
            return false;
        }
        catch (final IllegalReferenceCountException irce) {
            ThrowableUtil.addSuppressed(irce, this.leak.getCloseStackTraceIfAny());
            throw irce;
        }
    }
    
    private void closeLeak() {
        final boolean closed = this.leak.close(this.trackedByteBuf);
        assert closed;
    }
    
    @Override
    public ByteBuf order(final ByteOrder endianness) {
        if (this.order() == endianness) {
            return this;
        }
        return this.newSharedLeakAwareByteBuf(super.order(endianness));
    }
    
    private ByteBuf unwrappedDerived(final ByteBuf derived) {
        final ByteBuf unwrappedDerived = unwrapSwapped(derived);
        if (unwrappedDerived instanceof AbstractPooledDerivedByteBuf) {
            ((AbstractPooledDerivedByteBuf)unwrappedDerived).parent(this);
            return this.newLeakAwareByteBuf(derived, AbstractByteBuf.leakDetector.trackForcibly(derived));
        }
        return this.newSharedLeakAwareByteBuf(derived);
    }
    
    private static ByteBuf unwrapSwapped(ByteBuf buf) {
        if (buf instanceof SwappedByteBuf) {
            do {
                buf = buf.unwrap();
            } while (buf instanceof SwappedByteBuf);
            return buf;
        }
        return buf;
    }
    
    private SimpleLeakAwareByteBuf newSharedLeakAwareByteBuf(final ByteBuf wrapped) {
        return this.newLeakAwareByteBuf(wrapped, this.trackedByteBuf, this.leak);
    }
    
    private SimpleLeakAwareByteBuf newLeakAwareByteBuf(final ByteBuf wrapped, final ResourceLeakTracker<ByteBuf> leakTracker) {
        return this.newLeakAwareByteBuf(wrapped, wrapped, leakTracker);
    }
    
    protected SimpleLeakAwareByteBuf newLeakAwareByteBuf(final ByteBuf buf, final ByteBuf trackedByteBuf, final ResourceLeakTracker<ByteBuf> leakTracker) {
        return new SimpleLeakAwareByteBuf(buf, trackedByteBuf, leakTracker);
    }
}
