// Diesmal werden mehr vordefinierte Komponenten verwendet.
// Daher wird vorsichtshalber alles eingebunden. Der Stern *
// steht dabei als Joker für alle jeweils existierenden
// Komponenten.
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;



// Dieses Applet summiert Primzahlen zwischen einer unteren 
// und einer oberen Schranke. 
// Der Benutzer kann sowohl die Schranken angeben als auch, 
// jede wievielte Primzahl addiert werden soll.
public class SumPrim extends Applet
{
    // Da jetzt nicht nur die Methode  init  verwendet wird,
    // müssen die tatsächlich verwendeten Komponenten schon
    // an dieser Stelle deklariert werden. Nur dann können
    // wir sie auch in anderen Methoden verwenden.

    // Diese Komponenten haben die Aufgabe Eingaben vom
    // Benutzer entgegen zu nehmen. 

    // Der in diesen Textfeldern vom Benutzer eingetragenen
    // Werte sollen die untere und obere Schranke 
    // der Summation sein.
    TextField inputLimitLow;
    TextField inputLimitHigh;

    // Dieser Wert wird angeben, jede wievielte Primzahl 
    // addiert werden soll.
    TextField inputPrimStep;

    // Hier schreiben wir das Ergebnis rein.
    TextArea output;

    // Hier wollen wir Meldungen über den Status der 
    // Berechnung ausgeben.
    Label statusLabel;

    public void init()
    {
	// Zunächst werden die Elemente der GUI initialisiert.


        // Die ersten Komponenten sind Bezeichnungsfelder, 
	// die die Bedeutung der nachfolgenden Textfelder kurz erklären.
        Label labelLimitLow = new Label("Untere Schranke");
        Label labelLimitHigh = new Label("Obere Schranke");
        Label labelPrimStep = new Label("jede wievielte Primzahl");
	
	// Jetzt werden Ein- und Ausgabefelder initialisiert
	inputLimitLow = new TextField(8);
	inputLimitHigh = new TextField(8);
	inputPrimStep = new TextField(8);
	output = new TextArea(10, 20);
	output.setEditable(false);
	statusLabel = new Label("Warte auf Eingabe.            ");

	// Wir brauchen noch zwei Buttons um die Berechnung zu starten und 
	// die Eingabefelder zurückzusetzen 
	Button startButton = new Button("Start");
	Button resetButton = new Button("Reset");

        // Unseren Buttons muss nun noch mitgeteilt werden, was sie tun 
	// sollen, wenn sie angeklickt werden. 
        startButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent ae) {
		    // Der Startbutton soll mit der Berechnung beginnen.
		    calculateSum();
                }
        });

        resetButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent ae) {
		    // Der Resetbutton soll alle Felder zurücksetzen.
		    reset();
                }
        });


	// Als nächstes müssen wir dafür sorgen, dass unsere 
	// GUI-Elemente auch von unserem Applet angezeigt werden. 
	// Außerdem sollen sie "schön" angeordnet werden. 

	// Die Hauptanordnung übernimmt das bereits bekannte BorderLayout.
	// Damit werden die drei Hauptbereiche unseres Applets aufgeteilt:
	// Eingabe-Bereich, Ausgabe-Bereich und Status-Zeile
        setLayout(new BorderLayout());

        // Das Layout unseres Applets muss wissen, wo es den
        // Textbereich platzieren soll. Wir geben hier vor,
        // dass es in die (Neue) Mitte soll.
        add(output, BorderLayout.CENTER);

	// Die Statuszeile soll ganz unten erscheinen.
	add(statusLabel, BorderLayout.SOUTH);

        // Um die ganzen Bedienelemente anordnen zu können,
	// werden diese in einem Panel gruppiert, das zunächst 
	// noch erzeugt werden muss.
        Panel userPanel = new Panel();

        // Dieses Panel soll ganz oben im Applet erscheinen
        add(userPanel, BorderLayout.NORTH);

	// Die Eingabe-Elemente dieses Panels sollen wie in einem Gitter 
	// angeordnet werden.
	// Deshalb erzeugen wir ein GridLayout, das dem Panel zugeordnet wird.
	// Die erste Zahl (=3) gibt an, dass 3 Reihen vorhanden sein sollen.
	// Die zweite Zahl (=3) gibt an, dass 3 Spalten vorhanden sein sollen.
	// Die dritte Zahl (=20) gibt den Abstand in Pixeln an, der zwischen 
	// zwei Spalten eingefügt werden soll.
	// Die vierte Zahl (=20) gibt den Abstand in Pixeln an, der zwischen 
	// zwei Reihen eingefügt werden soll.
	userPanel.setLayout( new GridLayout(3, 3, 20, 20) );
	

	// Jetzt werden die Elemente des UserPanels zeilenweise 
	// hinzugefügt.
	userPanel.add(labelLimitLow);
	userPanel.add(inputLimitLow);
	userPanel.add(startButton);

	userPanel.add(labelLimitHigh);
	userPanel.add(inputLimitHigh);
	userPanel.add(resetButton);

	userPanel.add(labelPrimStep);
	userPanel.add(inputPrimStep);

    }


    // Diese Methode setzt die Ein- und Ausgabe-Felder in ihren 
    // Ur-Zustand surück.
    // Sie wird ausgeführt, wenn der Reset-Button gedrückt wird.
    private void reset() {
	
	// Die Benutzer-Eingaben werden gelöscht.
	inputLimitLow.setText("");
	inputLimitHigh.setText("");
	inputPrimStep.setText("");
	
	// Das Ausgabe-Feld wird gelöscht
	output.setText("");
	
	// Die Statuszeile wird zurückgesetzt
	statusLabel.setText("Warte auf Eingabe.");
    }


    // Diese Methode startet die Berechnung, sobald der Start-Button 
    // gedrückt wird. 
    private void calculateSum() {

	// Hier wird die Summe gespeichert.
        int sum=0;

	// Hier merken wir uns, wieviele Primzahlen wir schon gefunden haben.
        int prims=0;

	// Wir müssen zunächst die eingegebenen Werte lesen.
        int limitLow  = Integer.valueOf( inputLimitLow.getText() ).intValue();
        int limitHigh = Integer.valueOf( inputLimitHigh.getText() ).intValue();
        int primStep  = Integer.valueOf( inputPrimStep.getText() ).intValue();


	// Und dies ist die Zahl, die wir gerade untersuchen wollen.
	// Wir starten bei limitLow - 1, da wir dann einfach die nächst größere
	// Primzahl suchen können. 
	int actualNumber = limitLow - 1;

	// Werte <1 machen keinen Sinn!
	if (actualNumber<1) {
	    actualNumber = 1;
	}

	// Dies ist unsere aktuelle Primzahl;
	int prim = 0;

	// Ändere die Statuszeile
	statusLabel.setText("Berechnung läuft!");

	// Wir starten unsere Berechnung, die wir ausführen, solange wir 
	// nicht größer als limitHigh.
	// Zur Sicherheit prüfen wir, ob prinStep einen sinnvollen Wert hat (>0).
	while ( primStep>0 && actualNumber<=limitHigh ) {

	    // Wir suchen die nächste Primzahl. 
	    // Dazu verwenden wir den Program-Code aus der VL, der in der Methode
	    // findPrim steckt.
	    // Wir müssen dieser Methode mitteilen, ab welcher Zahl sie suchen soll.
	    // Dafür erhalten wir von ihr den Wert der nächsten Primzahl zurück. 
	    prim = findPrim(actualNumber);
	    
	    // Wir haben eine neue Primzahl gefunden.
	    prims++;
	    
	    // Falls diese Primzahl größer als unsere obere Schranke ist, können wir aufhören.
	    if (prim > limitHigh) {
		break;
	    }

	    // Falls diese primzahl die primStep-te ist, wird sie gezählt.
	    if ( prims % primStep == 0 ) {
		sum = sum + prim;
		output.append(" "+prim+"\n");
	    }
	    else {
		output.append(" \t("+prim+")\n");
	    }

	    // Nun wollen wir die nächst größere Primzahl berechnen.
	    actualNumber = prim;

	    // Das ist alles, was in einer Iteration zu tun ist.
	} 	    

	// Zum Schluß wird das Ergebnis ausgegeben.
	output.append("=====================\n");
	output.append(" "+sum+"\n\n");
		
	statusLabel.setText("Fertig!");
    }


    // Diese Methode berechnet zu einer gegebenen Zahl n 
    // die nächst größere Primzahl und gibt sie an das 
    // aufrufende Programmstück zurück.
    // Die Berechnung erfolgt genau wie in der Vorlesung.
    int findPrim (int n) {

	// --> Hier fehlt was:
	// --> Die Zahl n braucht nicht aus einem TextField 
	// --> gelesen zu werden, sondern wird direkt von dem
	// --> aufrufenden Programstück übergeben.

	
	// Boolean, indicates that a divisor 
	// k of z has been found
	boolean  divisorFound; 
	
	int z = n; // candidate for the prime, set to n+1, n+2 etc.
	do {
	    z++;
	    int k = 2;            // possible divisor of z
	    divisorFound = false; // so far no divisor of z found
            
	    while (!divisorFound && k*k <= z) {
		if (z % k == 0)   // check if k is a divisor of z
		    divisorFound = true;
		k++;
	    } // end of while
	}
	while (divisorFound);
	

	// --> Dies ist neu:
	// --> Hier wird der Wert von n an das aufrufende
	// --> Programstück zurückgegeben
	return z;
    }
}

