/**
 * Problema clásico del Productor-Consumidor con Buffer Acotado (LIFO / Pila).
 * Implementado mediante monitores de Java (synchronized, wait, notifyAll).
 */
class Buffer {
    private int cima, capacidad;
    private final int[] vector;

    public Buffer(int capacidad) {
        this.cima = 0;
        this.capacidad = capacidad;
        this.vector = new int[capacidad];
    }

    public synchronized int extraer(int id) {
        System.out.println("Consumidor " + id + ": espera para leer");
        while (cima == 0) {
            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return -1;
            }
        }
        int elem = vector[--cima];
        notifyAll();
        return elem;
    }

    public synchronized void insertar(int elem, int id) {
        System.out.println("Productor " + id + ": espera para insertar");
        while (cima == capacidad) {
            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
        }
        vector[cima++] = elem;
        notifyAll();
    }
}

class Consumidor extends Thread {
    private final Buffer buffer;
    private final int id;

    Consumidor(Buffer b, int numHilo) {
        this.buffer = b;
        this.id = numHilo;
        System.out.println("CONSUMIDOR " + id + ": entra");
    }

    @Override
    public void run() {
        int elem = buffer.extraer(id);
        System.out.println("Consumidor " + id + ": ha leido " + elem);
    }
}

class Productor extends Thread {
    private final Buffer buffer;
    private final int elem;
    private final int id;

    Productor(Buffer b, int elem, int numHilo) {
        this.buffer = b;
        this.elem = elem;
        this.id = numHilo;
        System.out.println("PRODUCTOR " + id + ": entra");
    }

    @Override
    public void run() {
        buffer.insertar(elem, id);
        System.out.println("Productor " + id + ": inserta " + elem);
    }
}

public class ProductorConsumidor {
    public static void main(String[] args) throws InterruptedException {
        Buffer buf = new Buffer(3);
        int numProds = 5;
        int numCons = 5;

        Thread[] prods = new Thread[numProds];
        Thread[] cons = new Thread[numCons];

        for (int i = 0; i < numProds; i++) {
            prods[i] = new Productor(buf, (i + 1) * 10, i + 1);
            prods[i].start();
        }

        // Breve pausa para dar paso a productores antes de los consumidores
        Thread.sleep(100);

        for (int j = 0; j < numCons; j++) {
            cons[j] = new Consumidor(buf, j + 1);
            cons[j].start();
        }

        for (Thread t : prods) t.join();
        for (Thread t : cons) t.join();

        System.out.println("Fin del hilo main: todas las transferencias completadas.");
    }
}
