import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Iterator;

public class Studentenverwaltung {

    private ArrayList<Student> studenten;
    private String semester = "Semester XXXX";

    public Studentenverwaltung() {
        Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); 
        studenten = new ArrayList<Student>();
    }

    public void hinzufuegen(Student neu) {
        this.studenten.add(neu);
    }

    public void steuern() {
        setUp();
        int ein = -1;
        EinUndAusgabe io = new EinUndAusgabe();
        while (ein != 0) {
            io.ausgeben("***" + this.semester + "***\n"
                + "N\u00e4chste Aktion:\n" + " (0) Programm beenden\n"
                + " (1) Neuen Studenten einf\u00fcgen\n"
                + " (2) Student mit Matrikelnummer suchen\n"
                + " (3) Studierendendaten \u00e4ndern\n"
                + " (4) Studierende pro Studiengang\n"
                + " (5) Student l\u00f6schen\n"
                + " (6) Studenten eines Fachs l\u00f6schen\n"
                + " (7) Neuen Austauschstudenten einf\u00fcgen\n"
                + " (8) Anzahl Austauschstudenten ausgeben \n"
                + " (9) Alle Studierenden anzeigen\n"
                + "(10) Semester eintragen\n" + "(11) Daten speichern\n"
                + "(12) Daten laden: ");
            ein = io.leseInteger();
            switch (ein) {
                case 0: {
                    break;
                }
                case 1: {
                    studentEingeben();
                    break;
                }
                case 2: {
                    studentSuchen();
                    break;
                }
                case 3: {
                    studentBearbeiten();
                    break;
                }
                case 4: {
                    studentenZaehlen();
                    break;
                }
                case 5: { // neu
                    studentLoeschen();
                    break;
                }
                case 6: {
                    studiengangLoeschen();
                    break;
                }
                case 7: {
                    austauschstudentenEingeben();
                    break;
                }
                case 8: {
                    anzahlAustauschstudentenAusgeben();
                    break;
                }
                case 9: {
                    studentenAusgeben();
                    break;
                }
                case 10: {
                    semesterAktualisieren();
                    break;
                }
                case 11: {
                    datenSpeichern();
                    break;
                }
                case 12: {
                    datenLaden();
                    break;
                }
                default: {
                    io.ausgeben("Zahl zwischen 0 und 8 eingeben\n");
                    break;
                }
            }
            io.ausgeben("\n");
        }
    }

    /*
     * Variante mit genauerer Prüfung public void datenLaden() { EinUndAusgabe
     * io = new EinUndAusgabe(); String datei = ""; Boolean fertig = false;
     * while (!datei.toUpperCase().equals("ENDE") && !fertig) { datei =
     * nichtLeererText("Dateiname (Abbruch mit \"Ende\")"); File file = new
     * File(datei); if (!datei.toUpperCase().equals("ENDE") && !file.canRead())
     * { io.ausgeben("Datei nicht lesbar.\n"); } else { fertig = true; } } if
     * (!datei.toUpperCase().equals("ENDE")) { datenLaden(datei); } }
     */

    public void datenLaden() {
        EinUndAusgabe io = new EinUndAusgabe();
        String datei = nichtLeererText("Dateiname (Abbruch mit \"Ende\")");
        if (datei.toUpperCase().equals("ENDE")) {
            return;
        }
        try {
            datenLaden(datei);
            io.ausgeben("Daten geladen.\n");
        } catch (FileNotFoundException e) {
            io.ausgeben("Problem beim Laden.\n");
        }
    }

    //@SuppressWarnings("unchecked")
    public void datenLaden(String datei) throws FileNotFoundException {
        XMLDecoder file = null;
        file = new XMLDecoder(new BufferedInputStream(
                new FileInputStream(datei)));
        this.semester = (String) file.readObject();
        this.studenten = (ArrayList<Student>) file.readObject();
        file.close();
    }

    //@SuppressWarnings("unchecked")
    public void datenLaden2(String datei) throws FileNotFoundException {
        XMLDecoder file = null;
        try {
            file = new XMLDecoder(new BufferedInputStream(new FileInputStream(
                        datei)));
            this.semester = (String) file.readObject();
            this.studenten = (ArrayList<Student>) file.readObject();
        } finally {
            if (file != null) {
                file.close();
            }
        }
    }

    public void datenSpeichern() {
        EinUndAusgabe io = new EinUndAusgabe();
        String datei = nichtLeererText("Dateiname (Abbruch mit \"Ende\")");
        if (!datei.toUpperCase().equals("ENDE")) {
            try {
                datenSpeichern3(datei);
                io.ausgeben("Speichern erfolgreich.\n");
            } catch (FileNotFoundException e) {
                io.ausgeben("Speicherproblem: " + e.getMessage() + "\n");
            } catch (IllegalArgumentException e) {
                io.ausgeben("Namensproblem: " + e.getMessage() + "\n");
            }
        }
    }

    public void datenSpeichern(String datei) throws FileNotFoundException {
        XMLEncoder file = null;
        file = new XMLEncoder(new BufferedOutputStream(new FileOutputStream(
                    datei)));
        file.writeObject(semester);
        file.writeObject(studenten);
        file.close();
    }

    public void datenSpeichern2(String datei) throws FileNotFoundException {
        XMLEncoder file = null;
        try {
            file = new XMLEncoder(new BufferedOutputStream(
                    new FileOutputStream(datei)));
            file.writeObject(semester);
            file.writeObject(studenten);
        } finally {
            if (file != null) {
                file.close();
            }
        }
    }

    public void datenSpeichern3(String datei) throws FileNotFoundException,
    IllegalArgumentException {
        if (!datei.startsWith("StudSave")) {
            throw new IllegalArgumentException("Dateianfang "
                + "mit StudSave ignoriert");
        }
        XMLEncoder file = null;
        file = new XMLEncoder(new BufferedOutputStream(new FileOutputStream(
                    datei)));
        file.writeObject(semester);
        file.writeObject(studenten);
        file.close();
    }

    public void datenSpeichern4(String datei) throws FileNotFoundException,
    DateinamenException {
        if (!datei.startsWith("StudSave")) {
            throw new DateinamenException();
        }
        XMLEncoder file = null;
        file = new XMLEncoder(new BufferedOutputStream(new FileOutputStream(
                    datei)));
        file.writeObject(semester);
        file.writeObject(studenten);
        file.close();
    }

    /*
     * public void datenSpeichernIdee(String datei) { XMLEncoder file = null;
     * file = new XMLEncoder( new BufferedOutputStream( new
     * FileOutputStream(datei))); file.writeObject(semester);
     * file.writeObject(studenten); file.close(); }
     */

    public void semesterAktualisieren() {
        this.semester = nichtLeererText("Welches Semester: ");
    }

    public void studentenAusgeben() {
        EinUndAusgabe io = new EinUndAusgabe();
        for (Student s : this.studenten) {
            io.ausgeben(s + "\n");
        }
        io.ausgeben("----------\n");
    }

    public void setUp() {
        Student s1 = new Student("Uwe", "X", 1987, "IMI", 424241);
        Student s2 = new Austauschstudent("CHN", "Xi", "Yu", 1988, "IMI",
                424242);
        Student s3 = new Austauschstudent("USA", "Mo", "Jo", 1989, "MID",
                424243);
        Student s4 = new Student("Uta", "B", 1987, "MID", 424244);
        hinzufuegen(s1);
        hinzufuegen(s2);
        hinzufuegen(s3);
        hinzufuegen(s4);
    }

    public void anzahlAustauschstudentenAusgeben() {
        EinUndAusgabe io = new EinUndAusgabe();
        io.ausgeben("Es gibt " + anzahlAustauschstudenten()
            + "Austauschstudenten\n");
    }

    public int anzahlAustauschstudenten() {
        int ergebnis = 0;
        for (Student s : this.studenten) {
            ergebnis = ergebnis + s.zaehlenAlsAustauschstudent();
        }
        return ergebnis;
    }

    public int anzahlAustauschstudentenNichtSoToll() {
        int ergebnis = 0;
        for (Student s : this.studenten) {
            if (s instanceof Austauschstudent) {
                ergebnis = ergebnis + 1;
            }
        }
        return ergebnis;
    }

    public void austauschstudentenEingeben() {
        Austauschstudent ergebnis = new Austauschstudent();
        ergebnis.setVorname(nichtLeererText("Vorname"));
        ergebnis.setNachname(nichtLeererText("Nachname"));
        ergebnis.setStudiengang(nichtLeererText("Studiengang"));
        ergebnis.setGeburtsjahr(zahlZwischen("Geburtsjahr", 1900, 2000));
        ergebnis.setMatrikelnummer(zahlZwischen("Matrikelnummer", 99999,
                1000000));
        ergebnis.setLand(nichtLeererText("Land"));
        studenten.add(ergebnis);
    }

    public void studentLoeschen() {
        int mat = zahlZwischen("Matrikelnummer", 99999, 1000000);
        studentloeschen(mat);
    }

    // mit Iterator löschen, recht einfach
    public void studentloeschen(int mat) {
        EinUndAusgabe io = new EinUndAusgabe();
        Iterator<Student> it = this.studenten.iterator();
        while (it.hasNext()) {
            Student tmp = it.next();
            if (tmp.getMatrikelnummer() == mat) {
                it.remove();
                io.ausgeben("Student gel\u00f6scht\n");
            }
        }
    }

    // mit einfacher for-Schleife; kritisch bearbeitete
    // Liste zu ändern, geht aber
    public void studentloeschen2(int mat) {
        EinUndAusgabe io = new EinUndAusgabe();
        for (int i = 0; i < this.studenten.size(); i++) {
            Student tmp = this.studenten.get(i);
            if (tmp.getMatrikelnummer() == mat) {
                this.studenten.remove(i);
                io.ausgeben("Student gel\u00f6scht\n");
            }
        }
    }

    // wirft: java.util.ConcurrentModificationException
    public void studentloeschenFalsch(int mat) {
        EinUndAusgabe io = new EinUndAusgabe();
        for (Student tmp : this.studenten) {
            if (tmp.getMatrikelnummer() == mat) {
                this.studenten.remove(tmp);
                io.ausgeben("Student gel\u00f6scht\n");
            }
        }
    }

    public void studentloeschen3(int mat) {
        EinUndAusgabe io = new EinUndAusgabe();
        Student weg = null;
        for (Student tmp : this.studenten) {
            if (tmp.getMatrikelnummer() == mat) {
                weg = tmp;
            }
        }
        if (weg != null) {
            this.studenten.remove(weg);
            io.ausgeben("Student gel\u00f6scht\n");
        }
    }

    public void studiengangLoeschen() {
        EinUndAusgabe io = new EinUndAusgabe();
        String fach = nichtLeererText("Studiengang: ");
        int anzahl = studiengangLoeschen(fach);
        io.ausgeben("Es werden " + anzahl + " Studenten gel\u00f6scht\n");
    }

    public int studiengangLoeschen(String fach) {
        ArrayList<Student> weg = new ArrayList<Student>();
        for (Student tmp : this.studenten) {
            if (tmp.getStudiengang().equals(fach)) {
                weg.add(tmp);
            }
        }
        for (Student tmp : weg) {
            this.studenten.remove(tmp);
        }
        return weg.size();
    }

    public void studentSuchen() {
        EinUndAusgabe io = new EinUndAusgabe();
        int mat = zahlZwischen("Matrikelnummer", 99999, 1000000);
        Student s = studentSuchen(mat);
        if (s != null) {
            io.ausgeben("Daten: " + s + "\n");
        } else {
            io.ausgeben("nicht gefunden\n");
        }
    }

    public Student studentSuchen(int mat) {
        Student ergebnis = null;
        for (Student s : this.studenten) {
            if (s.getMatrikelnummer() == mat) {
                ergebnis = s;
            }
        }
        return ergebnis;
    }

    public void studentBearbeiten() {
        EinUndAusgabe io = new EinUndAusgabe();
        int mat = zahlZwischen("Matrikelnummer", 99999, 1000000);
        Student s = studentSuchen(mat);
        if (s == null) {
            io.ausgeben("nicht gefunden\n");
            return;
        }
        String neuVor = nichtLeererText("neuer Vorname (" + "alt:"
                + s.getVorname() + ")");
        String neuNach = nichtLeererText("neuer Nachname (" + "alt:"
                + s.getNachname() + ")");
        s.setVorname(neuVor);
        s.setNachname(neuNach);
        io.ausgeben("neu: " + s);
    }

    public void studentenZaehlen() {
        EinUndAusgabe io = new EinUndAusgabe();
        String fach = nichtLeererText("Studiengang: ");
        int anzahl = studentenZaehlenIn(fach);
        io.ausgeben("in " + fach + ": " + anzahl + "\n");
    }

    public int studentenZaehlenIn(String fach) {
        int ergebnis = 0;
        for (Student s : this.studenten) {
            if (s.getStudiengang().equals(fach)) {
                ergebnis = ergebnis + 1;
            }
        }
        return ergebnis;
    }

    public int anzahl() {
        return this.studenten.size();
    }

    /*
     * geht nur, wenn equals sauber umgesetzt Boolean exitiertSchon(Student
     * studi){ return studenten.contains(studi); }
     */

    /*
     * erster Versuch public Student studentEingeben(){ Student ergebnis = new
     * Student(); EinUndAusgabe io = new EinUndAusgabe(); String tmpVorname =
     * ""; while(tmpVorname.equals("")){ io.ausgeben("Vorname: "); tmpVorname =
     * io.leseString(); } ergebnis.setVorname(tmpVorname); return ergebnis; }
     */

    public void studentEingeben() {
        Student ergebnis = new Student();
        ergebnis.setVorname(nichtLeererText("Vorname"));
        ergebnis.setNachname(nichtLeererText("Nachname"));
        ergebnis.setStudiengang(nichtLeererText("Studiengang"));
        ergebnis.setGeburtsjahr(zahlZwischen("Geburtsjahr", 1900, 2000));
        ergebnis.setMatrikelnummer(zahlZwischen("Matrikelnummer", 99999,
                1000000));
        this.studenten.add(ergebnis);
    }

    public String nichtLeererText2(String aufforderung) {
        String ergebnis = "";
        EinUndAusgabe io = new EinUndAusgabe();
        while (ergebnis.equals("")) {
            io.ausgeben(aufforderung + ": ");
            ergebnis = io.leseString();
            ergebnis = ergebnis.trim();
        }
        return ergebnis;
    }

    public String nichtLeererText(String aufforderung) {
        String ergebnis;
        EinUndAusgabe io = new EinUndAusgabe();
        do {
            io.ausgeben(aufforderung + ": ");
            ergebnis = io.leseString();
            ergebnis = ergebnis.trim();
        } while (ergebnis.equals(""));
        return ergebnis;
    }

    public int zahlZwischen(String aufforderung, int untereGrenze,
    int obereGrenze) {
        int ergebnis = untereGrenze - 1;
        EinUndAusgabe io = new EinUndAusgabe();
        while (ergebnis < untereGrenze || ergebnis > obereGrenze) {
            io.ausgeben(aufforderung + ": ");
            ergebnis = io.leseInteger();
        }
        return ergebnis;
    }

    public ArrayList<Student> getStudenten() {
        return this.studenten;
    }

    public void setStudenten(ArrayList<Student> studenten) {
        if (studenten != null) {
            this.studenten = studenten;
        }
    }

    public String getSemester() {
        return this.semester;
    }

    public void setSemester(String semester) {
        this.semester = semester;
    }

    public static void main(String[] s) {
        new Studentenverwaltung().steuern();
    }

}
