import java.util.ArrayList;
import static java.lang.Thread.sleep;
import java.util.Scanner;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

class Router {

    public boolean[] connected;
    public int maxDevices;
    public int currentConnectedDevices;
    public Semaphore semaphore;

    Router(int maxDevices) {
        this.maxDevices = maxDevices;
        semaphore = new Semaphore(maxDevices);
        connected = new boolean[maxDevices];
    }

    public synchronized int connect(Device device) throws InterruptedException {
        for (int i = 0; i < maxDevices; i++) {
            if (!connected[i]) {
                currentConnectedDevices++;
                device.setConnectionID(i + 1);
                connected[i] = true;
                sleep(50);
                break;
            }
        }
        return device.getConnectionID();
    }

    public synchronized void disconnect(Device device) {
        currentConnectedDevices--;
        connected[device.getConnectionID() - 1] = false;
        notify();
        String s ="Connection " + device.getConnectionID() + ": " + device.getName2() + " Logged out";
        Network.write(s);
        //System.out.println("Connection " + device.getConnectionID() + ": " + device.getName2() + " Logged out");
    }

    public synchronized void deviceArrived(Device device) {
        // System.out.println( device.getName2() +" (" + device.getType() + ")" +"
        // arrived");
    }
}

class Semaphore {

    private int value;

    public Semaphore(int value) {
        this.value = value;
    }

    public synchronized void waitUntilAvailable(Device device) throws InterruptedException {
        value--;
        if (value < 0) {
            String s =device.getName2() + " (" + device.getType() + ")" + " arrived and waiting";
            Network.write(s);
            //System.out.println(device.getName2() + " (" + device.getType() + ")" + " arrived and waiting");
            wait();

        } else {
            String s =device.getName2() + " (" + device.getType() + ")" + " arrived";
            Network.write(s);
            //System.out.println(device.getName2() + " (" + device.getType() + ")" + " arrived");
        }

        device.getRouter().connect(device);
    }

    public synchronized void signal() {
        value++;
        if (value <= 0) {
            notify();
        }
    }
}

class Device extends Thread {

    private String name;
    private String type;
    private int connectionID;
    private Router router;

    public Device(String name, String type, Router router) {
        this.name = name;
        this.type = type;
        this.router = router;
        connectionID = 1;
    }

    @Override
    public void run() {
        try {
            router.deviceArrived(this);
            router.semaphore.waitUntilAvailable(this);
            connectionID = router.connect(this);
            String s ="Connection " + connectionID + ": " + name + " Occupied";
            Network.write(s);
            //System.out.println("Connection " + connectionID + ": " + name + " Occupied");
            performActivity();
            router.disconnect(this);
            router.semaphore.signal();

        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public void performActivity() throws InterruptedException {
        String s ="Connection " + connectionID + ": " + name+" Login";
        Network.write(s);
        //System.out.println("Connection " + connectionID + ": " + name+" Login");
        String s2="Connection " + connectionID + ": " + name + " Performs online activity";
        Network.write(s2);
        //System.out.println("Connection " + connectionID + ": " + name + " Performs online activity");
        sleep(2000);
    }

    public String getName2() {
        return name;
    }

    public String getType() {
        return type;
    }

    public int getConnectionID() {
        return connectionID;
    }

    public void setConnectionID(int connectionID) {
        this.connectionID = connectionID;
    }

    public Router getRouter() {
        return router;
    }
}

public class Network {
    public static void write(String s){
        String fileName = "log.txt";
        try {
            BufferedWriter writer = new BufferedWriter(new FileWriter(fileName, true));
            writer.write(s);
            writer.newLine();
            writer.close();
        }
        catch (IOException e) {
            System.err.println("Error appending to the file: " + e.getMessage());
        }


    }
    public static void main(String[] args) throws InterruptedException {
        int numberOfConnections, numberOfDevices;
        ArrayList<Device> devices = new ArrayList<>();

        Scanner input = new Scanner(System.in);

        System.out.println("How many Wi-Fi connections are available?");
        numberOfConnections = input.nextInt();
        Router router = new Router(numberOfConnections);

        System.out.println("How many devices do clients want to connect?");
        numberOfDevices = input.nextInt();
        for (int i = 0; i < numberOfDevices; i++) {
            Device newDevice = new Device(input.next(), input.next(), router);
            devices.add(newDevice);
        }
        for (int i = 0; i < numberOfDevices; i++) {
            sleep(100);
            devices.get(i).start();
        }
    }
}شرح كل سطر بيعمل اي وازاي عمله