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

package com.hypixel.hytale.builtin.landiscovery;

import java.net.InetAddress;
import io.netty.buffer.ByteBuf;
import java.net.InetSocketAddress;
import java.net.SocketException;
import com.hypixel.hytale.server.core.util.io.ByteBufUtil;
import com.hypixel.hytale.server.core.universe.Universe;
import java.net.Inet6Address;
import java.net.Inet4Address;
import io.netty.buffer.ByteBufAllocator;
import com.hypixel.hytale.server.core.io.ServerManager;
import com.hypixel.hytale.common.util.ArrayUtil;
import java.net.DatagramPacket;
import java.nio.charset.StandardCharsets;
import com.hypixel.hytale.server.core.HytaleServer;
import java.util.logging.Level;
import java.net.MulticastSocket;
import javax.annotation.Nonnull;
import com.hypixel.hytale.logger.HytaleLogger;

class LANDiscoveryThread extends Thread
{
    private static final byte[] REPLY_HEADER;
    private static final byte[] REQUEST_HEADER;
    public static final int LAN_DISCOVERY_PORT = 5510;
    @Nonnull
    private final HytaleLogger LOGGER;
    private MulticastSocket socket;
    
    public LANDiscoveryThread() {
        super("LAN Discovery Listener");
        this.setDaemon(true);
        this.LOGGER = LANDiscoveryPlugin.get().getLogger();
    }
    
    @Override
    public void run() {
        try {
            (this.socket = new MulticastSocket(5510)).setBroadcast(true);
            this.LOGGER.at(Level.INFO).log("Bound to UDP 0.0.0.0:5510 for LAN discovery");
            String name = HytaleServer.get().getServerName();
            if (name.length() > 16377) {
                name = name.substring(0, 16377) + "...";
            }
            final byte[] serverName = name.getBytes(StandardCharsets.UTF_8);
            final byte[] receiveBuf = new byte[15000];
            final DatagramPacket packet = new DatagramPacket(receiveBuf, receiveBuf.length);
            while (!this.isInterrupted()) {
                this.socket.receive(packet);
                if (ArrayUtil.startsWith(packet.getData(), LANDiscoveryThread.REQUEST_HEADER)) {
                    final InetSocketAddress publicAddress = ServerManager.get().getNonLoopbackAddress();
                    if (publicAddress == null) {
                        continue;
                    }
                    final ByteBuf buf = ByteBufAllocator.DEFAULT.buffer();
                    buf.writeBytes(LANDiscoveryThread.REPLY_HEADER);
                    buf.writeByte(0);
                    final InetAddress address = publicAddress.getAddress();
                    if (address == null || address.isLoopbackAddress()) {
                        this.LOGGER.at(Level.WARNING).log("No public address to send as response!");
                    }
                    else {
                        if (address instanceof Inet4Address) {
                            buf.writeByte(4);
                        }
                        else {
                            if (!(address instanceof Inet6Address)) {
                                this.LOGGER.at(Level.WARNING).log("Unrecognized target address class %s: %s", address.getClass(), address);
                                continue;
                            }
                            buf.writeByte(16);
                        }
                        buf.writeBytes(address.getAddress());
                        buf.writeShortLE(publicAddress.getPort());
                        buf.writeShortLE(serverName.length);
                        buf.writeBytes(serverName);
                        buf.writeIntLE(Universe.get().getPlayerCount());
                        final int maxPlayers = HytaleServer.get().getConfig().getMaxPlayers();
                        buf.writeIntLE(Math.max(maxPlayers, 0));
                        final byte[] sendData = ByteBufUtil.getBytesRelease(buf);
                        final DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, packet.getAddress(), packet.getPort());
                        this.socket.send(sendPacket);
                        this.LOGGER.at(Level.FINE).log("Was discovered by %s:%d", packet.getAddress(), packet.getPort());
                    }
                }
            }
        }
        catch (final SocketException e) {
            if (!"Socket closed".equalsIgnoreCase(e.getMessage()) && !"Socket is closed".equalsIgnoreCase(e.getMessage())) {
                this.LOGGER.at(Level.SEVERE).withCause(e).log("Exception in lan discovery listener:");
            }
        }
        catch (final Throwable t) {
            this.LOGGER.at(Level.SEVERE).withCause(t).log("Exception in lan discovery listener:");
        }
        finally {
            if (this.socket != null) {
                this.socket.close();
            }
        }
        this.LOGGER.at(Level.INFO).log("Stopped listing on UDP 0.0.0.0:5510 for LAN discovery");
    }
    
    public MulticastSocket getSocket() {
        return this.socket;
    }
    
    static {
        REPLY_HEADER = "HYTALE_DISCOVER_REPLY".getBytes(StandardCharsets.US_ASCII);
        REQUEST_HEADER = "HYTALE_DISCOVER_REQUEST".getBytes(StandardCharsets.US_ASCII);
    }
}
