package net.minecraft.network;

import io.netty.util.concurrent.GenericFutureListener;
import io.netty.channel.Channel;
import net.minecraft.network.protocol.Packet;

class NetworkManager {
#if version >= 1.8.4
    public Channel channel;
#elseif version >= 1.8.3
    public Channel channel:k;
#else
    private Channel channel:i;
#endif

#if version >= 1.9
    public boolean isConnected();
#else
    public boolean isConnected:g();
#endif

    // Only used on 1.20.2+ in the callback for a QueuedPacket
#if version >= 1.21.6
    private void queue_sendPacketImpl:sendPacket((Object) Packet<?> packet, (Object) io.netty.channel.ChannelFutureListener packetsendlistener, boolean flush);
#elseif version >= 1.20.2
    private void queue_sendPacketImpl:sendPacket((Object) Packet<?> packet, (Object) PacketSendListener packetsendlistener, boolean flush);
#else
    private void queue_sendPacketImpl((Object) Object packet, (Object) Object packetsendlistener, boolean flush) {
        throw new UnsupportedOperationException("This method is only for 1.20.2+");
    }
#endif

    // Unsafe! May not function under some conditions!
    // Returns true if queuing was successful, false otherwise
    public static boolean queuePacketUnsafe((Object) NetworkManager networkManager, Object packet) {
#if version >= 1.8.3 && version < 1.13.2 && !exists net.minecraft.network.NetworkManager private final readonly java.util.Queue i;
        // Paper 1.11.2 did away with the queue entirely, so it's not supported
        return false;
#else
        // Should work here
  #if version >= 1.20.2
        #require net.minecraft.network.NetworkManager private final readonly java.util.Queue packetQueue:pendingActions;
  #elseif version >= 1.17
        #require net.minecraft.network.NetworkManager private final readonly java.util.Queue packetQueue:queue;
  #elseif version >= 1.13.2
        #require net.minecraft.network.NetworkManager private final readonly java.util.Queue packetQueue;
  #elseif version >= 1.8.3
        #require net.minecraft.network.NetworkManager private final readonly java.util.Queue packetQueue:i;
  #else
        #require net.minecraft.network.NetworkManager private final readonly java.util.Queue packetQueue:h;
  #endif
        java.util.Queue queue = networkManager#packetQueue;

        Object queuedPacket;
  #if version >= 1.21.6
    #if exists net.minecraft.network.NetworkManager.PacketSendAction
        #require net.minecraft.network.NetworkManager.PacketSendAction private net.minecraft.network.NetworkManager.PacketSendAction createQueuedPacket:<init>(net.minecraft.network.protocol.Packet<?> packet, io.netty.channel.ChannelFutureListener listener, boolean flush);
        queuedPacket = #createQueuedPacket((net.minecraft.network.protocol.Packet) packet, (io.netty.channel.ChannelFutureListener) null, false);
    #else
        #if paper
            #warning Connection PacketSendAction class was not identified, errors might occur queueing packets!
        #endif
        queuedPacket = new com.bergerkiller.bukkit.common.internal.proxy.QueuedPacket_1_20_2(packet, null, false);
    #endif
  #elseif version >= 1.20.2
    #if exists net.minecraft.network.NetworkManager.PacketSendAction
        #require net.minecraft.network.NetworkManager.PacketSendAction private net.minecraft.network.NetworkManager.PacketSendAction createQueuedPacket:<init>(net.minecraft.network.protocol.Packet<?> packet, net.minecraft.network.PacketSendListener listener, boolean flush);
        queuedPacket = #createQueuedPacket((net.minecraft.network.protocol.Packet) packet, (net.minecraft.network.PacketSendListener) null, false);
    #else
        #if version >= 1.20.5 && paper
            #warning Connection PacketSendAction class was not identified, errors might occur queueing packets!
        #endif
        queuedPacket = new com.bergerkiller.bukkit.common.internal.proxy.QueuedPacket_1_20_2(packet, null, false);
    #endif
  #elseif exists net.minecraft.network.NetworkManager.QueuedPacket public NetworkManager.QueuedPacket(net.minecraft.network.protocol.Packet<?> packet, io.netty.util.concurrent.GenericFutureListener listener)
        #require net.minecraft.network.NetworkManager.QueuedPacket public NetworkManager.QueuedPacket createQueuedPacket:<init>((Object) Packet<?> packet, GenericFutureListener listener);
        queuedPacket = #createQueuedPacket(packet, (GenericFutureListener) null);
  #elseif exists net.minecraft.network.NetworkManager.QueuedPacket public NetworkManager.QueuedPacket(net.minecraft.network.protocol.Packet<?> packet, io.netty.util.concurrent.GenericFutureListener[] listener)
        #require net.minecraft.network.NetworkManager.QueuedPacket public NetworkManager.QueuedPacket createQueuedPacket:<init>((Object) Packet<?> packet, GenericFutureListener[] listener);
        queuedPacket = #createQueuedPacket(packet, (GenericFutureListener[]) null);
  #elseif exists net.minecraft.network.NetworkManager.QueuedPacket public NetworkManager.QueuedPacket(net.minecraft.network.protocol.Packet<?> packet, net.minecraft.network.PacketSendListener listener)
        #require net.minecraft.network.NetworkManager.QueuedPacket public NetworkManager.QueuedPacket createQueuedPacket:<init>((Object) Packet<?> packet, net.minecraft.network.PacketSendListener listener);
        queuedPacket = #createQueuedPacket(packet, (net.minecraft.network.PacketSendListener) null);
  #else
        #error Cannot queue packets - queued packet constructor not found!
  #endif

  #if version >= 1.20.2
        // Can just add to it (is a Concurrent Linked Queue)
        queue.add(queuedPacket);
  #elseif version >= 1.14.4
        // Uses synchronized
        synchronized (queue) {
            queue.add(queuedPacket);
        }
  #elseif version >= 1.8.3 && exists net.minecraft.network.NetworkManager private final java.util.concurrent.locks.ReentrantReadWriteLock j;
        // Uses ReentrantReadWriteLock
        #require net.minecraft.network.NetworkManager private final java.util.concurrent.locks.ReentrantReadWriteLock packetQueueRWLock:j;
        java.util.concurrent.locks.ReentrantReadWriteLock lock = networkManager#packetQueueRWLock;
        lock.writeLock().lock();
        try {
            queue.add(queuedPacket);
        } finally {
            lock.writeLock().unlock();
        }
  #else
        // No lock at all (relies on concurrent queue logic)
        // Also used on 1.8.8 PandaSpigot
        queue.add(queuedPacket);
  #endif
        return true;
#endif
    }
}
