// Path: src/main/java/com/github/games647/lagmonitor/traffic/Reflection.java
// public interface FieldAccessor<T> {
// 
//     /**
//      * Retrieve the content of a field.
//      *
//      * @param target - the target object, or NULL for a static field.
//      * @return The value of the field.
//      */
//     T get(Object target);
// 
//     /**
//      * Set the content of a field.
//      *
//      * @param target - the target object, or NULL for a static field.
//      * @param value - the new value of the field.
//      */
//     void set(Object target, Object value);
// 
//     /**
//      * Determine if the given object has this field.
//      *
//      * @param target - the object to test.
//      * @return TRUE if it does, FALSE otherwise.
//      */
//     boolean hasField(Object target);
// }


import com.github.games647.lagmonitor.traffic.Reflection.FieldAccessor;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
            // Damn you, late bind
            Bukkit.getScheduler().runTask(plugin, () -> {
                registerChannelHandler();
                plugin.getLogger().info("[TinyProtocol] Late bind injection successful.");
            });
        }
    }

    private void createServerChannelHandler() {
        serverChannelHandler = new ChannelInboundHandlerAdapter() {

            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) {
                Channel channel = (Channel) msg;

                channel.pipeline().addLast(new ChannelDuplexHandler() {
                    @Override
                    public void channelRead(ChannelHandlerContext handlerContext, Object object) throws Exception {
                        onChannelRead(handlerContext, object);
                        super.channelRead(handlerContext, object);
                    }

                    @Override
                    public void write(ChannelHandlerContext handlerContext, Object object, ChannelPromise promise)
                            throws Exception {
                        onChannelWrite(handlerContext, object, promise);
                        super.write(handlerContext, object, promise);
                    }
                });

// Path: src/main/java/com/github/games647/lagmonitor/traffic/Reflection.java
// public interface FieldAccessor<T> {
// 
//     /**
//      * Retrieve the content of a field.
//      *
//      * @param target - the target object, or NULL for a static field.
//      * @return The value of the field.
//      */
//     T get(Object target);
// 
//     /**
//      * Set the content of a field.
//      *
//      * @param target - the target object, or NULL for a static field.
//      * @param value - the new value of the field.
//      */
//     void set(Object target, Object value);
// 
//     /**
//      * Determine if the given object has this field.
//      *
//      * @param target - the object to test.
//      * @return TRUE if it does, FALSE otherwise.
//      */
//     boolean hasField(Object target);
// }


// Path: src/main/java/com/github/games647/lagmonitor/traffic/TinyProtocol.java
import com.github.games647.lagmonitor.traffic.Reflection.FieldAccessor;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;

            // Damn you, late bind
            Bukkit.getScheduler().runTask(plugin, () -> {
                registerChannelHandler();
                plugin.getLogger().info("[TinyProtocol] Late bind injection successful.");
            });
        }
    }

    private void createServerChannelHandler() {
        serverChannelHandler = new ChannelInboundHandlerAdapter() {

            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) {
                Channel channel = (Channel) msg;

                channel.pipeline().addLast(new ChannelDuplexHandler() {
                    @Override
                    public void channelRead(ChannelHandlerContext handlerContext, Object object) throws Exception {
                        onChannelRead(handlerContext, object);
                        super.channelRead(handlerContext, object);
                    }

                    @Override
                    public void write(ChannelHandlerContext handlerContext, Object object, ChannelPromise promise)
                            throws Exception {
                        onChannelWrite(handlerContext, object, promise);
                        super.write(handlerContext, object, promise);
                    }
                });

                ctx.fireChannelRead(msg);