package protocolsupport.protocol.pipeline.version.v_pe;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.connection.DownstreamBridge;
import net.md_5.bungee.connection.UpstreamBridge;
import net.md_5.bungee.netty.PipelineUtils;
import protocolsupport.api.Connection;
import protocolsupport.injector.BungeeNettyChannelInjector.CustomHandlerBoss;
import protocolsupport.protocol.packet.handler.PEEntityRewriteDownstreamBridge;
import protocolsupport.protocol.packet.handler.PEEntityRewriteUpstreamBridge;
import protocolsupport.protocol.pipeline.IPipeLineBuilder;
import protocolsupport.protocol.pipeline.common.PacketCompressor;
import protocolsupport.protocol.pipeline.common.PacketDecompressor;
import protocolsupport.protocol.storage.NetworkDataCache;
import protocolsupport.protocol.utils.EncapsulatedProtocolUtils;
import protocolsupport.utils.ReflectionUtils;

public class PipeLineBuilder extends IPipeLineBuilder {

	@Override
	public void buildBungeeClientCodec(Channel channel, Connection connection) {
		ChannelPipeline pipeline = channel.pipeline();
		NetworkDataCache cache = new NetworkDataCache();
		pipeline.replace(PipelineUtils.PACKET_DECODER, PipelineUtils.PACKET_DECODER, new FromClientPacketDecoder(connection, cache));
		pipeline.replace(PipelineUtils.PACKET_ENCODER, PipelineUtils.PACKET_ENCODER, new ToClientPacketEncoder(connection, cache));
		pipeline.get(CustomHandlerBoss.class).setPacketHandlerChangeListener(listener -> {
			try {
				return (listener instanceof UpstreamBridge) ? new PEEntityRewriteUpstreamBridge(ProxyServer.getInstance(), ReflectionUtils.getFieldValue(listener, "con")) : listener;
			} catch (IllegalArgumentException | IllegalAccessException e) {
				throw new RuntimeException(e);
			}
		});
	}

	@Override
	public void buildBungeeClientPipeLine(Channel channel, Connection connection) {
		throw new UnsupportedOperationException("Only connection through encapsulation protocol is supported");
	}

	@Override
	public void buildBungeeServer(Channel channel, Connection connection) {
		ChannelPipeline pipeline = channel.pipeline();
		pipeline.addFirst(new ChannelInboundHandlerAdapter() {
			@Override
			public void channelActive(ChannelHandlerContext ctx) throws Exception {
				ctx.writeAndFlush(EncapsulatedProtocolUtils.createHandshake(null, true));
				super.channelActive(ctx);
			}
		});
		NetworkDataCache cache = new NetworkDataCache();
		pipeline.replace(PipelineUtils.PACKET_DECODER, PipelineUtils.PACKET_DECODER, new FromServerPacketDecoder(connection, cache));
		pipeline.replace(PipelineUtils.PACKET_ENCODER, PipelineUtils.PACKET_ENCODER, new ToServerPacketEncoder(connection, cache));
		pipeline.addAfter(PipelineUtils.FRAME_PREPENDER, "compress", new PacketCompressor(256));
		pipeline.addAfter(PipelineUtils.FRAME_DECODER, "decompress", new PacketDecompressor());
		pipeline.get(CustomHandlerBoss.class).setPacketHandlerChangeListener(listener -> {
			try {
				return (listener instanceof DownstreamBridge) ? new PEEntityRewriteDownstreamBridge(ProxyServer.getInstance(), ReflectionUtils.getFieldValue(listener, "con")) : listener;
			} catch (IllegalArgumentException | IllegalAccessException e) {
				throw new RuntimeException(e);
			}
		});
	}

}

@@ -50,16 +50,81 @@
 .v_pe;%0A%0A
+import io.netty.buffer.ByteBuf;%0Aimport io.netty.buffer.Unpooled;%0A
 import i
@@ -290,16 +290,157 @@
 peline;%0A
+import io.netty.handler.timeout.IdleState;%0Aimport io.netty.handler.timeout.IdleStateEvent;%0Aimport io.netty.handler.timeout.IdleStateHandler;%0A
 import n
@@ -1077,32 +1077,96 @@
 etDecompressor;%0A
+import protocolsupport.protocol.serializer.VarNumberSerializer;%0A
 import protocols
@@ -2843,32 +2843,599 @@
 orkDataCache();%0A
+%09%09pipeline.addFirst(%22idlestatehandler%22, new IdleStateHandler(0, 5, 0));%0A%09%09pipeline.addAfter(%22idlestatehandler%22, %22keepalive%22, new ChannelInboundHandlerAdapter() %7B%0A%09%09%09@Override%0A%09%09%09public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception %7B%0A%09%09%09%09if (evt instanceof IdleStateEvent) %7B%0A%09%09%09%09%09if (((IdleStateEvent) evt).state() == IdleState.WRITER_IDLE) %7B%0A%09%09%09%09%09%09ByteBuf rawemptyframedpacket = Unpooled.buffer();%0A%09%09%09%09%09%09VarNumberSerializer.writeVarInt(rawemptyframedpacket, 0);%0A%09%09%09%09%09%09ctx.writeAndFlush(rawemptyframedpacket);%0A%09%09%09%09%09%7D%0A%09%09%09%09%7D%0A%09%09%09%7D%0A%09%09%7D);%0A
 %09%09pipeline.repla

Add keepalives to bungee->server pe connection