import java.util.*;
import java.util.concurrent.*;
import java.util.random.RandomGenerator;

class Ship implements Runnable{

    public String _name;
    public int _capacity;
    public int _anboard;
    public  ShipPort _shipPort;
    public boolean isLoading; //0 - выгружается

    public Ship(String _name, int _capacity, int _anboard, ShipPort shipPort, boolean isLoading) {
        this._name = _name;
        this._capacity = _capacity;
        this._anboard = _anboard;
        this._shipPort = shipPort;
        this.isLoading = isLoading;

        new Thread(this).start();
    }

    @Override
    public void run() {
        if(isLoading){
            _shipPort.Load(this);
        }
        else
            _shipPort.Unload(this);
    }
}

class ShipPort {
    private int _capacity;
    private Integer _storage;
    public final Semaphore _semaphore = new Semaphore(3);

    public ShipPort(int _storage, int _capacity) {
        this._capacity = _capacity;
        this._storage = _storage;
    }

    public void Unload(Ship ship) {
        int maxLoad = 0;
        try {
            System.out.printf("!!!!!!!!!!!!!!'%s' выгрузка %s\n", ship._name, ship._anboard);
            _semaphore.acquire();
            Thread.sleep(2000);

            synchronized (_storage) {



                if (this._storage + ship._anboard > _capacity) {
                    maxLoad = this._capacity - this._storage;
                    this._storage = this._capacity;
                } else {
                    maxLoad = ship._anboard;
                    this._storage += ship._anboard;
                }

                System.out.printf(
                        "'%s' выгрузили %s" +
                        "\n" +
                        "в порту: %s \n" +
                        "очередь = %s \n" +
                        "------------------------\n",
                        ship._name, maxLoad, this._storage, _semaphore.getQueueLength());
            }

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
                _semaphore.release();
        }
    }

    public void Load(Ship ship) {
        int maxLoad = ship._capacity - ship._anboard;
        try {
            System.out.printf("!!!!!!!!!!!!'%s' загрузить %s\n", ship._name, maxLoad);
            _semaphore.acquire();

            Thread.sleep(2000);
            synchronized (_storage) {
                if (this._storage - maxLoad < 0) {
                    ship._anboard += maxLoad;
                    this._storage = 0;
                } else {
                    ship._anboard += maxLoad;
                    this._storage -= maxLoad;
                }

                System.out.printf(
                        "'%s' загрузили %s" +
                                "\n" +
                                "в порту: %s \n" +
                                "очередь = %s \n" +
                                "------------------------\n",
                        ship._name, maxLoad, this._storage, _semaphore.getQueueLength()
                );
            }

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
                _semaphore.release();
        }
    }

}

public class Main {
    public static void main(String[] args) {
        Random random = new Random();

        ShipPort shipPort = new ShipPort(50, 100);
        for (int i = 1; i<=100; i++){
            int shipCapacity = random.nextInt(2, 60);
            new Ship("Корабль" + i, shipCapacity, random.nextInt(1, shipCapacity), shipPort, random.nextBoolean());
            //new Ship("Корабль" + i, i*2, i, shipPort, random.nextBoolean());
            //new Ship("Корабль" + i, i*2, i, shipPort, true);
        }
    }
}
