public class AplikasiPenyimpan {
    public static void main(String[] args) {
        // Implementasi generik lanjut: T diteruskan, tidak dikunci
        PenyimpanMemori<String> memo = new PenyimpanMemori<>();
        memo.simpan("Budi");
        memo.simpan("Siti");
        System.out.println("Memo    : jumlah " + memo.jumlah());
        System.out.println("Ambil   : " + memo.ambil() + ", sisa " + memo.jumlah());

        PenyimpanMemori<Integer> stok = new PenyimpanMemori<>();
        stok.simpan(12);
        stok.simpan(7);
        System.out.println("Stok    : jumlah " + stok.jumlah());
        System.out.println("Ambil   : " + stok.ambil() + ", sisa " + stok.jumlah());

        // Implementasi konkret: type parameter dikunci menjadi String
        PenyimpanRiwayat riwayat = new PenyimpanRiwayat(2);
        riwayat.simpan("login");
        riwayat.simpan("unggah");
        riwayat.simpan("logout");
        System.out.println("Riwayat : " + riwayat.tampilkan());

        // Polymorphism lewat variabel bertipe interface generik
        Penyimpan<String> sebagai = riwayat;
        System.out.println("Interface: jumlah " + sebagai.jumlah());
    }
}

class PenyimpanRiwayat implements Penyimpan<String> {
    private final java.util.ArrayDeque<String> tumpukan = new java.util.ArrayDeque<>();
    private final int kapasitas;

    PenyimpanRiwayat(int kapasitas) {
        this.kapasitas = kapasitas;
    }

    @Override
    public void simpan(String nilai) {
        if (tumpukan.size() == kapasitas) {
            tumpukan.pollFirst();   // buang peristiwa paling lama
        }
        tumpukan.addLast(nilai);
    }

    @Override
    public String ambil() {
        return tumpukan.peekLast();
    }

    @Override
    public int jumlah() {
        return tumpukan.size();
    }

    public String tampilkan() {
        return tumpukan.toString();
    }
}
