import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class KunciOtomatis {

    public static void main(String[] args) {
        TabelMini tabel = new TabelMini();

        System.out.println("== INSERT satu per satu ==");
        System.out.println("id produk baru : " + tabel.insert("Buku Java", "150000"));
        System.out.println("id produk baru : " + tabel.insert("Mouse", "250000"));

        System.out.println();
        System.out.println("== getGeneratedKeys setelah INSERT ==");
        StatementMini st = tabel.createStatement(true);   // padanan RETURN_GENERATED_KEYS
        st.executeUpdate("INSERT INTO produk (nama, harga) VALUES ('Monitor', '1200000')");
        try (KunciHasil kunci = st.getGeneratedKeys()) {
            while (kunci.next()) {
                System.out.println("kunci          : " + kunci.getLong(1));
            }
        }

        System.out.println();
        System.out.println("== Kunci dari batch ==");
        StatementMini st2 = tabel.createStatement(true);
        st2.addBatch("INSERT INTO produk (nama, harga) VALUES ('Kabel HDMI', '75000')");
        st2.addBatch("INSERT INTO produk (nama, harga) VALUES ('Web Camera', '350000')");
        st2.executeBatch();
        try (KunciHasil kunci = st2.getGeneratedKeys()) {
            while (kunci.next()) {
                System.out.println("kunci batch    : " + kunci.getLong(1));
            }
        }

        System.out.println();
        System.out.println("== Statement tanpa permintaan kunci ==");
        StatementMini st3 = tabel.createStatement(false);
        try {
            st3.getGeneratedKeys();
        } catch (IllegalStateException e) {
            System.out.println("DITOLAK: " + e.getMessage());
        }

        System.out.println();
        System.out.println("== Isi tabel akhir ==");
        tabel.cetak();
    }
}

/** Tabel produk dengan kolom identitas: id naik otomatis tiap INSERT. */
class TabelMini {

    private final List<String[]> baris = new ArrayList<>();
    private final AtomicInteger urut = new AtomicInteger();

    long insert(String nama, String harga) {
        long id = urut.incrementAndGet();
        baris.add(new String[]{String.valueOf(id), nama, harga});
        return id;
    }

    StatementMini createStatement(boolean mintaKunci) {
        return new StatementMini(this, mintaKunci);
    }

    void cetak() {
        System.out.println("| id | nama       | harga   |");
        for (String[] b : baris) {
            System.out.printf("| %-2s | %-10s | %-7s |%n", b[0], b[1], b[2]);
        }
    }
}

/** Statement mini yang bisa "meminta kunci" saat dibuat. */
class StatementMini implements AutoCloseable {

    private final TabelMini tabel;
    private final boolean mintaKunci;
    private final List<String> antrian = new ArrayList<>();
    private final List<Long> kunci = new ArrayList<>();

    StatementMini(TabelMini tabel, boolean mintaKunci) {
        this.tabel = tabel;
        this.mintaKunci = mintaKunci;
    }

    int executeUpdate(String sql) {
        Matcher m = Pattern
                .compile("INSERT INTO produk \\(nama, harga\\) VALUES \\('([^']+)', '([^']+)'\\)")
                .matcher(sql);
        if (!m.matches()) {
            throw new IllegalArgumentException("SQL tidak dikenal: " + sql);
        }
        long id = tabel.insert(m.group(1), m.group(2));
        if (mintaKunci) {
            kunci.add(id);
        }
        return 1;
    }

    void addBatch(String sql) {
        antrian.add(sql);
    }

    int[] executeBatch() {
        System.out.println("[batch] " + antrian.size() + " pernyataan dieksekusi");
        int[] hasil = new int[antrian.size()];
        for (int i = 0; i < antrian.size(); i++) {
            hasil[i] = executeUpdate(antrian.get(i));
        }
        antrian.clear();
        return hasil;
    }

    KunciHasil getGeneratedKeys() {
        if (!mintaKunci) {
            throw new IllegalStateException(
                    "getGeneratedKeys() ditolak: statement dibuat tanpa permintaan kunci");
        }
        return new KunciHasil(new ArrayList<>(kunci));
    }

    @Override
    public void close() {
        // tidak ada resource nyata pada shim ini
    }
}

/** Padanan ResultSet kunci: satu kolom, kursor berbasis next(). */
class KunciHasil implements AutoCloseable {

    private final List<Long> kunci;
    private int kursor = -1;

    KunciHasil(List<Long> kunci) {
        this.kunci = kunci;
    }

    boolean next() {
        if (kursor < kunci.size()) {
            kursor++;
        }
        return kursor < kunci.size();
    }

    long getLong(int indeks) {
        if (indeks != 1) {
            throw new IllegalArgumentException("kolom kunci hanya ada satu");
        }
        if (kursor < 0 || kursor >= kunci.size()) {
            throw new IllegalStateException("kursor tidak berada pada baris yang valid");
        }
        return kunci.get(kursor);
    }

    @Override
    public void close() {
        // tidak ada resource nyata pada shim ini
    }
}
