package com.github.steveice10.packetlib.tcp;

import com.github.steveice10.packetlib.Session;
import com.github.steveice10.packetlib.event.session.PacketErrorEvent;
import com.github.steveice10.packetlib.event.session.PacketReceivedEvent;
import com.github.steveice10.packetlib.io.NetInput;
import com.github.steveice10.packetlib.io.NetOutput;
import com.github.steveice10.packetlib.packet.Packet;
import com.github.steveice10.packetlib.tcp.io.ByteBufNetInput;
import com.github.steveice10.packetlib.tcp.io.ByteBufNetOutput;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;

import java.util.List;

public class TcpPacketCodec extends ByteToMessageCodec<Packet> {
    private Session session;

    public TcpPacketCodec(Session session) {
        this.session = session;
    }

    @Override
    public void encode(ChannelHandlerContext ctx, Packet packet, ByteBuf buf) throws Exception {
        try {
            NetOutput out = new ByteBufNetOutput(buf);

            this.session.getPacketProtocol().getPacketHeader().writePacketId(out, this.session.getPacketProtocol().getOutgoingId(packet));
            packet.write(out);
        } catch(Throwable t) {
            PacketErrorEvent e = new PacketErrorEvent(this.session, t);
            this.session.callEvent(e);
            if(!e.shouldSuppress()) {
                throw t;
            }
        }
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) throws Exception {
        Packet packet;
        try {
            NetInput in = new ByteBufNetInput(buf);

            int initial = buf.readerIndex();
            int id = this.session.getPacketProtocol().getPacketHeader().readPacketId(in);
            if(id == -1) {
                buf.readerIndex(initial);
                return;
            }

            packet = this.session.getPacketProtocol().createIncomingPacket(id);
            packet.read(in);

            if(buf.readableBytes() > 0) {
                throw new IllegalStateException("Packet \"" + packet.getClass().getSimpleName() + "\" not fully read.");
            }
        } catch(Throwable t) {
            PacketErrorEvent e = new PacketErrorEvent(this.session, t);
            this.session.callEvent(e);
            if(!e.shouldSuppress()) {
                throw t;
            }

            return;
        }

        if(packet.isPriority()) {
            this.session.callEvent(new PacketReceivedEvent(this.session, packet));
        }

        out.add(packet);
    }
}

@@ -954,32 +954,74 @@
 ows Exception %7B%0A
+        int initial = buf.writerIndex();%0A%0A
         try %7B%0A  
@@ -1010,32 +1010,32 @@
 %0A%0A        try %7B%0A
-
             NetO
@@ -1267,32 +1267,154 @@
 (Throwable t) %7B%0A
+            // Reset writer index to make sure incomplete data is not written out.%0A            buf.writerIndex(initial);%0A%0A
             Pack
@@ -1711,32 +1711,74 @@
 ows Exception %7B%0A
+        int initial = buf.readerIndex();%0A%0A
         Packet p
@@ -1855,53 +1855,8 @@
 );%0A%0A
-            int initial = buf.readerIndex();%0A
     
@@ -2328,32 +2328,32 @@
 ;%0A            %7D%0A
-
         %7D catch(
@@ -2359,32 +2359,195 @@
 (Throwable t) %7B%0A
+            // Advance buffer to end to make sure remaining data in this packet is skipped.%0A            buf.readerIndex(buf.readerIndex() + buf.readableBytes());%0A%0A
             Pack

Make sure bad packet data is skipped when errors are suppressed.