import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.*;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.*;

public class udp_extended {
    public static class GreeterServer extends Thread {
        private final AtomicBoolean asToStop = new AtomicBoolean(false);
        private static int port = 0;
        DatagramSocket socket = null;
        byte[] buf = new byte[256];

        private Map<InetAddress, List<Integer>> ipNumbersMap;

        private void addNumber(InetAddress ip, int nombre) {
            ipNumbersMap.putIfAbsent(ip, new ArrayList<>());
            ipNumbersMap.get(ip).add(nombre);
        }

        private double averageNumber(InetAddress ip) {
            if (ipNumbersMap.containsKey(ip)) {
                List<Integer> nombres = ipNumbersMap.get(ip);

                int somme = 0;
                for (int nombre : nombres) {
                    somme += nombre;
                }

                if (!nombres.isEmpty()) {
                    return (double) somme / nombres.size();
                }
            }
            return 0;
        }

        public GreeterServer(int port_number, String name) throws SocketException {
            port = port_number;
            this.setName(name);
            this.start();
        }

        public void stopThread() {
            this.asToStop.set(true);
        }

        @Override
        public void run() {
            try {
                socket = new DatagramSocket(port);
            } catch (SocketException e) {
                throw new RuntimeException(e);
            }

            ipNumbersMap = new HashMap<>();

            System.out.println("["+this.getName()+"] Listening on port "+ port +"...");

            while(!this.asToStop.get()) {
                DatagramPacket inPacket  = new DatagramPacket(buf, buf.length);
                try {
                    socket.receive(inPacket);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                String received = new String(inPacket.getData(), 0, inPacket.getLength());
                System.out.println("["+this.getName()+"] ["+inPacket.getAddress()+":"+inPacket.getPort()+"] " + received);

                try {
                    this.addNumber(inPacket.getAddress(), Integer.parseInt(received));
                    System.out.println("["+this.getName()+"] -> "+this.averageNumber(inPacket.getAddress()));
                } catch (NumberFormatException e) {
                    if (received.equals("stop")) {
                        this.stopThread();
                        System.out.println("[" + this.getName() + "] End listening");
                        continue;
                    }
                }

                InetAddress senderAddress = inPacket.getAddress();
                int senderPort = inPacket.getPort();
                DatagramPacket outPacket = new DatagramPacket(buf, buf.length, senderAddress, senderPort);
                try {
                    socket.send(outPacket);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            socket.close();
        }
    }

    public static void sendSomething(String senderAddr, int senderPort, String name) throws IOException {
        byte[] buf = new byte[256];
        buf = name.getBytes();

        DatagramSocket socket = new DatagramSocket(12345);

        DatagramPacket inPacket  = new DatagramPacket(buf, buf.length);
        DatagramPacket outPacket = new DatagramPacket(buf, buf.length, InetAddress.getByName(senderAddr), senderPort);
        socket.send(outPacket);

        socket.close();
    }

    private static String readFromConsole() throws IOException {
        // System.in is an InputStream which we wrap into the more capable BufferedReader
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        while (true) {
            String input = reader.readLine();
            return input;
        }
    }

    public static void main(String[] args) {
        GreeterServer server = null;
        try {
            server = new GreeterServer(25565, "Server1");
        } catch (SocketException e) {
            throw new RuntimeException(e);
        }

        try {
            while(true) {
                String n = readFromConsole();
                sendSomething("127.0.0.1", 25565, n);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}