import imp.*;               // Alles aus IMP Unterordner
import javafx.fxml.*;       // FXML Definitionen 
import javafx.scene.control.*;  // Jedes Control-Element
import javafx.scene.layout.*;   // Alle Layout-Definitionen
import javafx.event.*;      // Button und Menu-Events
import javafx.stage.*;          // Dateiöffnen / Speichern-Dialog
import java.io.File;        // Dateihandling
import javafx.scene.control.Alert.AlertType;

public class Controller {

    @FXML
    private HBox hauptbereich;

    @FXML
    private PictureViewer viewer;

    @FXML
    private Slider slZoom;

    @FXML
    private Label lDateiname;

    // Eigene Attribute
    private FileChooser dateidialog;
    private GeometrischeBildoperationen algo_geometrisch;
    private Punktoperationen algo_punkt;
    private Mehrpixeloperationen algo_mehrpixel;
    private Kunst algo_kunst;
    private HSBFarbmodell algo_hsb;
    private Histogramme algo_histogramme;
    private Bildkombinationen algo_bildkombinationen;
    private Bitebenen algo_bitebenen;
    private GeometrischeBildoperationen2 algo_geometrisch2;


    private boolean schonInitialisiert;

    public Controller() {
        schonInitialisiert = false;
    }

    public void initialize() {
        if (!schonInitialisiert) { // noch nicht initialisiert?

            dateidialog = new FileChooser();
            dateidialog.setInitialDirectory(new File("images"));

            algo_geometrisch = new GeometrischeBildoperationen();
            algo_geometrisch2 = new GeometrischeBildoperationen2();
            algo_punkt = new Punktoperationen();
            algo_mehrpixel = new Mehrpixeloperationen();
            algo_kunst = new Kunst();
            algo_hsb = new HSBFarbmodell();
            algo_histogramme = new Histogramme();
            algo_bildkombinationen = new Bildkombinationen();
            algo_bitebenen = new Bitebenen();


            slZoom.valueProperty().addListener((observable, oldValue, newValue) -> zoom());
            schonInitialisiert = true;
        }
    }

    void zoom() {
        // Auslesen von Control-Elementen  
        double zoom = slZoom.getValue();

        // Control-Elemente anpassen
        viewer.setZoom(zoom);
    }

    @FXML
    void bZurueck(ActionEvent event) {
        viewer.back();
    }

    @FXML
    void mBeenden(ActionEvent event) {
        // Frage nach Fenster und schließe dieses
        Stage stage = (Stage) hauptbereich.getScene().getWindow();
        stage.close();
    }

    @FXML
    void mBildOeffnen(ActionEvent event) {
        File file = dateidialog.showOpenDialog(null);
        if (file != null) {
            Picture neuesBild = new Picture(file.getAbsolutePath());
            viewer.setImage(neuesBild, true);
            lDateiname.setText(file.getAbsolutePath());
        }
    }

    @FXML
    void mBildSpeichern(ActionEvent event) {
        File file = dateidialog.showSaveDialog(null);
        if (file != null) {
            Picture aktuellesBild = viewer.getImage();
            aktuellesBild.save(file.getAbsolutePath());
            lDateiname.setText(file.getAbsolutePath());
        }
    }

    @FXML
    void mDreheLinks(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_geometrisch.dreheLinks(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mDreheRechts(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_geometrisch.dreheRechts(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mFarbanpassung(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 

        optionenAnzeigen("farbanpassung.fxml");

        // Sichere aktuelles Bild
        viewer.pushImage();

        sRotanteil.valueProperty().addListener(  (observable, oldValue, newValue) -> farbanpassung(aktuellesBild) );
        sGruenanteil.valueProperty().addListener(  (observable, oldValue, newValue) -> farbanpassung(aktuellesBild) );
        sBlauanteil.valueProperty().addListener(  (observable, oldValue, newValue) -> farbanpassung(aktuellesBild) );
    }

    @FXML
    void mFindeHorizontaleKanten(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_mehrpixel.kantenfindenHorizontal(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mFindeKanten(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_mehrpixel.kantenfinden(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mFindeVertikaleKanten(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_mehrpixel.kantenfindenVertikal(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mGraustufenMaximum(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_punkt.graustufenMax(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mGraustufenMinimum(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_punkt.graustufenMin(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mGraustufenMittelwert(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_punkt.graustufenDurchschnitt(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mGraustufenNatuerlich(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_punkt.graustufenNatuerlich(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mNurBlaukanal(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_punkt.farbaenderung(aktuellesBild,0.0,0.0,1.0);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mNurGruenkanal(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_punkt.farbaenderung(aktuellesBild,0.0,1.0,0.0);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mNurRotkanal(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_punkt.farbaenderung(aktuellesBild,1.0,0.0,0.0);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mRelief(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_mehrpixel.relief(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mSchaerfen(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_mehrpixel.schaerfen(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern

    }

    @FXML
    void mSpiegleHorizontal(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_geometrisch.spiegelHorizontal(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mSpiegleVertikal(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_geometrisch.spiegelVertikal(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mTauschGruenBlau(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_punkt.tauschGruenBlau(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mTauschRotBlau(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_punkt.tauschRotBlau(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mTauschRotGruen(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_punkt.tauschRotGruen(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern
    }

    @FXML
    void mUeber(ActionEvent event) {
        Alert alert = new Alert(AlertType.INFORMATION);
        alert.setTitle("Über mein Programm ...");
        alert.setHeaderText(null);
        alert.setContentText("Dieses Programm wurde erstellt von :\nThomas Schaller (ZPG IMP)\nVersion 1.0, Januar 2020");

        alert.showAndWait();
    }

    @FXML
    void mWeichzeichnen(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_mehrpixel.weichzeichnen(aktuellesBild);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern

    }

    @FXML
    void mWeichzeichnen31x31(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_mehrpixel.weichzeichnen(aktuellesBild,31);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern

    }

    @FXML
    void mWeichzeichnenGauss31x31(ActionEvent event) {
        // Auslesen von Control-Elementen
        Picture aktuellesBild = viewer.getImage(); 
        // Berechnung durchführen
        Picture neuesBild = algo_mehrpixel.gaussfilter(aktuellesBild,31);
        // Control-Elemente anpassen
        viewer.setImage(neuesBild, true);  // true = altes Bild speichern

    }

    @FXML
    void mZurueck(ActionEvent event) {
        viewer.back();
    }

    // Zusätzliche Eingabe-Optionen ----------------------------------------------

    void optionenAnzeigen(String fxmlFile) {
        try {  // try-catch ist notwendig, um Fehler durch fehlende Dateien abzufangen.

            // Ist noch ein alter Eingabebereich sichtbar       
            if(hauptbereich.getChildren().size()>1) {
                viewer.back();  // Verwirf aktuelles Bild
                hauptbereich.getChildren().remove(1);  // Lösche Eingabebereich
            }

            // Lade neuen Eingabebereich
            FXMLLoader loader = new FXMLLoader( 
                    getClass().getResource("view/"+fxmlFile));
            loader.setController(this);
            VBox filterFenster = (VBox) loader.load();

            // Zeige Eingabebereich an
            hauptbereich.getChildren().add(filterFenster);

        } 
        catch(Exception e)    {
            System.out.println(e);
        }     
    }

    @FXML
    public void bAusfuehren(ActionEvent event) {
        hauptbereich.getChildren().remove(1);
    }

    @FXML
    public void bAbbrechen(ActionEvent event) {
        viewer.back();
        hauptbereich.getChildren().remove(1);
    }

    // ----------------- Farbanpassung -------------------

    @FXML
    private Slider sRotanteil;

    @FXML
    private Slider sGruenanteil;

    @FXML
    private Slider sBlauanteil;

    void farbanpassung(Picture altesBild) {
        double faktorRot   = sRotanteil.getValue();
        double faktorGruen = sGruenanteil.getValue();
        double faktorBlau  = sBlauanteil.getValue();

        Picture neuesBild  = algo_punkt.farbaenderung(altesBild,  
                faktorRot, faktorGruen, faktorBlau);

        viewer.setImage(neuesBild, false); 
    }

    // ----------------- Farbanpassung -------------------
    @FXML
    private Slider sDicke;

    @FXML
    private Slider sLaenge;

    @FXML
    private Slider sGroesse;

    @FXML
    private NumberField nfAnzahl;

    @FXML
    void mStricheln(ActionEvent event) {
        Picture alt = viewer.getImage();
        viewer.pushImage();

        optionenAnzeigen("stricheln.fxml");

        sLaenge.valueProperty().addListener((observable, oldValue, newValue) -> stricheln(alt));
        sDicke.valueProperty().addListener((observable, oldValue, newValue) -> stricheln(alt));
        nfAnzahl.textProperty().addListener((observable, oldValue, newValue) -> stricheln(alt));
        stricheln(alt);

    }

    void stricheln(Picture altesBild) {
        int laenge = (int) sLaenge.getValue();
        int dicke = (int) sDicke.getValue();
        int anzahl = nfAnzahl.getIntValue();
        Picture neu = algo_kunst.stricheln(altesBild,laenge,dicke,anzahl);
        viewer.setImage(neu, false); 
    }

    @FXML
    void mTupfen(ActionEvent event) {
        Picture alt = viewer.getImage();
        viewer.pushImage();

        optionenAnzeigen("tupfen.fxml");

        sGroesse.valueProperty().addListener((observable, oldValue, newValue) -> tupfen(alt));
        nfAnzahl.textProperty().addListener((observable, oldValue, newValue) -> tupfen(alt));
        tupfen(alt);
    }

    void tupfen(Picture altesBild) {
        int groesse = (int)sGroesse.getValue();
        int anzahl = nfAnzahl.getIntValue();

        Picture neu = algo_kunst.tupfen(altesBild,groesse,anzahl);
        viewer.setImage(neu, false);    
    }

    // -------------- HSB Farbmodell --------------------------
    @FXML
    private Slider sHue;

    @FXML
    private Slider sSaturation;

    @FXML
    private Slider sBrightness;

    @FXML
    void mGraustufenHSB(ActionEvent event) {
        Picture alt = viewer.getImage();

        Picture neu = algo_hsb.graustufenHSB(alt);

        viewer.setImage(neu, true);
    }

    @FXML
    void mFarbanpassungHSB(ActionEvent event) {
        Picture alt = viewer.getImage();
        viewer.pushImage();

        optionenAnzeigen("farbanpassung_hsb.fxml");

        sHue.valueProperty().addListener((observable, oldValue, newValue) -> farbanpassungHSB(alt));
        sSaturation.valueProperty().addListener((observable, oldValue, newValue) -> farbanpassungHSB(alt));
        sBrightness.valueProperty().addListener((observable, oldValue, newValue) -> farbanpassungHSB(alt));
        farbanpassungHSB(alt);
    }

    void farbanpassungHSB(Picture altesBild) {
        double dHue = sHue.getValue();
        double fSaturation = sSaturation.getValue();
        double fBrightness = sBrightness.getValue();

        Picture neu = algo_hsb.farbaenderungHSB(altesBild,dHue, fSaturation, fBrightness);
        viewer.setImage(neu, false);    
    }

    // -------------- Histogrammanpassung --------------------------
    @FXML
    private PictureViewer histogramm;

    @FXML
    private Slider sGamma;

    @FXML
    private Slider sUntereGrenze;

    @FXML
    private Slider sObereGrenze;

    @FXML
    void mLineareHistogrammanpassung(ActionEvent event) {
        Picture alt = viewer.getImage();
        viewer.pushImage();

        optionenAnzeigen("linearehistogrammanpassung.fxml");

        int[] haeufigkeiten = algo_histogramme.haeufigkeitsverteilung(alt);
        Picture histo = algo_histogramme.zeichneHistogramm(haeufigkeiten);
        histogramm.setImage(histo,false);

        sUntereGrenze.valueProperty().addListener((observable, oldValue, newValue) -> lineareHistogrammanpassung(alt));
        sObereGrenze.valueProperty().addListener((observable, oldValue, newValue) -> lineareHistogrammanpassung(alt));
    }

    @FXML
    void mGammakorrektur(ActionEvent event) {
        Picture alt = viewer.getImage();
        viewer.pushImage();

        optionenAnzeigen("gammakorrektur.fxml");

        int[] haeufigkeiten = algo_histogramme.haeufigkeitsverteilung(alt);
        Picture histo = algo_histogramme.zeichneHistogramm(haeufigkeiten);
        histogramm.setImage(histo,false);

        sGamma.valueProperty().addListener((observable, oldValue, newValue) -> gammakorrektur(alt));
    }

    @FXML
    void mAutomatischeHistogrammaequilisation(ActionEvent event) {
        Picture alt = viewer.getImage();
        Picture neu = algo_histogramme.automatischeHistogrammaequilisation(alt);
        viewer.setImage(neu,true);
    }

    void lineareHistogrammanpassung(Picture altesBild) {
        int untereGrenze = (int) sUntereGrenze.getValue();
        int obereGrenze = (int) sObereGrenze.getValue();

        Picture neu = algo_histogramme.lineareHistogrammanpassung(altesBild, untereGrenze, obereGrenze);
        viewer.setImage(neu, false);    
    }

    void gammakorrektur(Picture altesBild) {
        double gamma =  sGamma.getValue();

        Picture neu = algo_histogramme.gammakorrektur(altesBild, gamma);
        int[] haeufigkeiten = algo_histogramme.haeufigkeitsverteilung(neu);
        Picture histo = algo_histogramme.zeichneHistogramm(haeufigkeiten);
        histogramm.setImage(histo,false);

        viewer.setImage(neu, false);    
    }

    // ----------------------- Bildkombinationen -------------------------
    @FXML
    void mBildAddieren(ActionEvent event) {
        Picture bild1 = viewer.getImage();
        File file = dateidialog.showOpenDialog(null);
        if (file != null) {
            Picture bild2 = new Picture(file.getAbsolutePath());
            Picture neu = algo_bildkombinationen.addition(bild1,bild2);
            viewer.setImage(neu,true);
        }
    }

    @FXML
    void mUnterschied(ActionEvent event) {
        Picture bild1 = viewer.getImage();
        File file = dateidialog.showOpenDialog(null);
        if (file != null) {
            Picture bild2 = new Picture(file.getAbsolutePath());
            Picture diff1 = algo_bildkombinationen.differenz(bild1,bild2);
            Picture diff2 = algo_bildkombinationen.differenz(bild2,bild1);
            Picture neu = algo_bildkombinationen.addition(diff1, diff2);
            viewer.setImage(neu,true);
        }
    }

    @FXML
    void mMaskeLinear(ActionEvent event) {
        Picture bild1 = viewer.getImage();

        // Maske 
        //Picture bild2 = new Picture("images/maske1.jpg");
        // oder:
        int breite = bild1.getWidth();
        int hoehe  = bild1.getHeight();
        Picture bild2 = new Picture(breite, hoehe);
        for(int i=0; i < breite; i++) {
            bild2.stroke(i*255/breite);
            bild2.line(i,0, i,hoehe);
        }

        Picture neu = algo_bildkombinationen.multiplikation(bild1,bild2);
        viewer.setImage(neu,true);
    }    

    @FXML
    void mMaskeRadial(ActionEvent event) {
        Picture bild1 = viewer.getImage();
        Picture bild2 = new Picture("images/maske2.jpg");
        Picture neu = algo_bildkombinationen.multiplikation(bild1,bild2);
        viewer.setImage(neu,true);
    }    

    // ----------------------- Bitebenen -------------------------
    //@FXML
    //private PictureViewer histogramm;    schon bei Histogrammen definiert

    @FXML
    private Slider sGrenze;

    @FXML
    void mSchwarzWeiss(ActionEvent event) {
        Picture alt = viewer.getImage();
        viewer.pushImage();

        optionenAnzeigen("schwarzweiss.fxml");

        int[] haeufigkeiten = algo_histogramme.haeufigkeitsverteilung(alt);
        Picture histo = algo_histogramme.zeichneHistogramm(haeufigkeiten);
        histogramm.setImage(histo,false);

        sGrenze.valueProperty().addListener((observable, oldValue, newValue) -> schwarzweiss(alt));
        schwarzweiss(alt);
    }

    void schwarzweiss(Picture altesBild) {
        int grenze = (int) sGrenze.getValue();

        Picture neu = algo_bitebenen.schwarzweiss(altesBild, grenze);
        viewer.setImage(neu, false);    
    }

    @FXML
    private CheckBox cbBitebene1;
    @FXML
    private CheckBox cbBitebene2;
    @FXML
    private CheckBox cbBitebene3;
    @FXML
    private CheckBox cbBitebene4;
    @FXML
    private CheckBox cbBitebene5;
    @FXML
    private CheckBox cbBitebene6;
    @FXML
    private CheckBox cbBitebene7;
    @FXML
    private CheckBox cbBitebene8;

    @FXML
    private CheckBox cbSchwarzweiss;

    @FXML
    void mBitebenen(ActionEvent event) {
        Picture alt = viewer.getImage();
        viewer.pushImage();        

        optionenAnzeigen("bitebenen.fxml");

        cbBitebene1.selectedProperty().addListener((observable, oldValue, newValue) -> bitebenen(alt));
        cbBitebene2.selectedProperty().addListener((observable, oldValue, newValue) -> bitebenen(alt));
        cbBitebene3.selectedProperty().addListener((observable, oldValue, newValue) -> bitebenen(alt));
        cbBitebene4.selectedProperty().addListener((observable, oldValue, newValue) -> bitebenen(alt));
        cbBitebene5.selectedProperty().addListener((observable, oldValue, newValue) -> bitebenen(alt));
        cbBitebene6.selectedProperty().addListener((observable, oldValue, newValue) -> bitebenen(alt));
        cbBitebene7.selectedProperty().addListener((observable, oldValue, newValue) -> bitebenen(alt));
        cbBitebene8.selectedProperty().addListener((observable, oldValue, newValue) -> bitebenen(alt));
        cbSchwarzweiss.selectedProperty().addListener((observable, oldValue, newValue) -> bitebenen(alt));

    }

    void bitebenen(Picture altesBild) {
        boolean[] ebenen = new boolean[8];

        ebenen[0] = cbBitebene1.isSelected();
        ebenen[1] = cbBitebene2.isSelected();
        ebenen[2] = cbBitebene3.isSelected();
        ebenen[3] = cbBitebene4.isSelected();
        ebenen[4] = cbBitebene5.isSelected();
        ebenen[5] = cbBitebene6.isSelected();
        ebenen[6] = cbBitebene7.isSelected();
        ebenen[7] = cbBitebene8.isSelected();

        boolean sw = cbSchwarzweiss.isSelected();

        Picture neu = new Picture(altesBild.getWidth(), altesBild.getHeight(), "000000");
        for(int i = 0; i <8 ; i++) {
            if(ebenen[i]) {
                Picture bitebene =  algo_bitebenen.bitEbene(altesBild, i+1);
                neu = algo_bildkombinationen.addition(neu,bitebene ) ;
            }
        }

        if (sw) neu = algo_bitebenen.schwarzweiss(neu, 1);

        viewer.setImage(neu, false);    
    }

    @FXML
    private TextArea taNachricht;

    @FXML
    void mSteganographie(ActionEvent event) {
        optionenAnzeigen("Steganographie.fxml");
    }

    @FXML
    void bAufdecken(ActionEvent event) {
        Picture alt = viewer.getImage();
        Picture neu = algo_bitebenen.steganographie_ermitteln(alt);
        viewer.setImage(neu, true);
        hauptbereich.getChildren().remove(1);    
    }

    @FXML
    void bVerstecken(ActionEvent event) {
        Picture alt = viewer.getImage();
        String nachricht = taNachricht.getText();
        Picture neu = algo_bitebenen.steganographie_verstecken(alt, nachricht);
        viewer.setImage(neu, true);
        hauptbereich.getChildren().remove(1);

    }

    // ----------------------- geometrische Bildoperationen 2 ----------------------
    @FXML
    private NumberField tAltX;

    @FXML
    private NumberField tAltY;

    @FXML
    private NumberField tNeuX;

    @FXML
    private NumberField tNeuY;

    @FXML
    void mBildgroesseAendern(ActionEvent event) {
        Picture alt = viewer.getImage();
        viewer.pushImage();        

        optionenAnzeigen("bildgroesse.fxml");

        tAltX.setValue(alt.getWidth());
        tNeuX.setValue(alt.getWidth());
        tAltY.setValue(alt.getHeight());
        tNeuY.setValue(alt.getHeight());

        tNeuX.textProperty().addListener((observable, oldValue, newValue) -> bildgroesseAendern(alt));
        tNeuY.textProperty().addListener((observable, oldValue, newValue) -> bildgroesseAendern(alt));

    }

    void bildgroesseAendern(Picture altesBild) {
        int x = tNeuX.getIntValue();
        int y = tNeuY.getIntValue();
        if( x>0 && y>0) {
            Picture neu = algo_geometrisch2.groesseAendern(altesBild, x, y ) ;

            viewer.setImage(neu, false);    
        }
    }

    @FXML
    private Slider sWinkel;

    @FXML
    void mBildDrehen(ActionEvent event) {
        Picture alt = viewer.getImage();
        viewer.pushImage();        

        optionenAnzeigen("drehen.fxml");

        sWinkel.valueProperty().addListener((observable, oldValue, newValue) -> drehen(alt));
    }
    void drehen(Picture altesBild) {
        double winkel =  sWinkel.getValue();
        Picture neu = algo_geometrisch2.dreheBild(altesBild, winkel ) ;

        viewer.setImage(neu, false);    
    }
    
    @FXML
    void mBildVerwirbeln(ActionEvent event) {
        Picture alt = viewer.getImage();
        viewer.pushImage();        

        optionenAnzeigen("drehen.fxml");

        sWinkel.valueProperty().addListener((observable, oldValue, newValue) -> wirbel(alt));
    }
    
    void wirbel(Picture altesBild) {
        double winkel =  sWinkel.getValue();
        Picture neu = algo_geometrisch2.wirbel(altesBild, winkel ) ;

        viewer.setImage(neu, false);    
    }
    
    
   
}
