/*
 * Eprog Übung 01
 * WS 2002/03
 * Aufgabe 1136 ; Testen eines Satzes auf korrekte Syntax
 * Schwierigkeitsgrad : schwer
 * Autor : Maciej Salamon
 * Matrikelnr.: 0225708
 */

/* Das Programm liest einen Satz als Folge von Worten ein, überprueft die vorgeschriebenen Syntax - Regeln
 * und gibt als Ausgabe ein "J" bei korrekter Syntax, ansonsten die Meldung "FALSCHE EINGABE" aus.
 */

// das Package eprog für die Ein/Ausgabe wird importiert
import eprog.*;
// die Klasse Vector stellt eine Art dynamisches Array zur Verfügung
import java.util.Vector;

public class Satz extends EprogIO  {
    // hier beginnt die Ausführung
    public static void main(String[] args) {
	// Satz einlesen
	String[] satz = einlesen();
	// hier wird die Endausgabe ermittelt
	String ergebnis = satzTesten(satz);
	// Ergebnis ausgeben
	println(ergebnis);
    }// Ende main - Methode
// **********************************************************************

    // diese Methode liest den Satz ein
    // es werden solange Worte eingelesen, bis ein Wort mit einem Punkt am Ende eingelesen wird
    private static String[] einlesen() {
	// hier könnte man prinzipiell einen Array verwenden wenn man es aber genau nimmt,
	// ist die Anzahl der Worte unbekannt und daher eine sichere Array - Definition unmöglich
	// Vector kann dynamisch vergrößert werden
	Vector wortTabelle = new Vector();

	// hier werden die Wörter eingelesen, bis eines mit Endpunkt erreicht wird
	while (true) {
	    String ein = readWord();
	    wortTabelle.add(ein);
	    if (ein.endsWith(".")) {
		break;
	    }
	} // Ende while - Schleife
	// da ein Array zum Arbeiten besser ist als ein Vector (schneller), wird die Eingabe
	//entsprechend umgewandelt
	String[] rueckgabe = new String[wortTabelle.size()];
	for (int i = 0; i < wortTabelle.size() ; i++) {
	    rueckgabe[i] = (String)wortTabelle.elementAt(i);
	}
	// der String - Array wird zurückgegeben
	return rueckgabe;
    } // Ende einlesen - Methode
// *************************************************************************

    // diese Methode überprüft die Syntax des eingegebenen Textes
    // sie gibt entweder am Ende vom Durchlauf ein "J" zurück,
    // oder wird früher verlassen und gibt "FALSCHE EINGABE" zurück
    private static String satzTesten(String[] satz){

	// die Konstante für den Fehlertext wird festgelegt
	final String fehler = "FALSCHE EINGABE";

	// Anzahl der Worte wird ueberprueft, erlaubt sind fünf
	if (satz.length > 5) {
	    return fehler;
	}
	// Hilfsvariablen definieren
	boolean klammer = false,
	    anfZeichen = false,     // für Anführungszeichen
	    strichpunkt = false;
	boolean satzAnfang = true,
	    wortAnfang = true;
	int buchstabe = 0;          // hier wird die Anzahl der Buchstaben im Wort festgehalten

	// alle Woerter abarbeiten
	// "Satzschleife"
	for (int w = 0 ; w < satz.length ; w ++ ) {

	    // das Wort wird in einen character - array umgewandelt
	    char[] wort = new char[satz[w].length()];
	    wort = satz[w].toCharArray();

	    // alle Zeichen im Wort abarbeiten
	    // Wortschleife:
	    for (int z = 0; z < wort.length   ;z++ ) {

		// das aktuelle Zeichen entnehmen
		char zeichen = wort[z];

		// Ist das Zeichen erlaubt ?
		if (!istBuchstabe(zeichen) && welchSonder(zeichen) == -1) {
		    // offensichtlich kein zugelassenes Zeichen
		    return fehler;
		}

		// zeichen ist ein Buchstabe
		if (istBuchstabe(zeichen)) {
		    // am Satzanfang darf kein Kleinbuchstabe stehen
		    if (satzAnfang) {
			if (istKl(zeichen)) {
			    return fehler;
			} // es ist also ein Grossbuchstabe
			else {
			    satzAnfang = false;
			}
		    } // Ende Satzanfanguntersuchung

		    // zeichen ist ein Grossbuchstabe
		    if (istGr(zeichen)) {
			// ein Grossbuchstabe darf nur am Anfang vom Wort stehen
			if (!wortAnfang) {
			    return fehler;
			}
			// erster Buchstabe im Wort
			buchstabe = 1;
			wortAnfang = false;
		    } // Ende Grossbuchstabe
		    // sonst Kleinbuchstabe
		    else {
			// Anzahl der Buchstaben erhöhen
			buchstabe++;
			// ein Wort darf bis zu 12 Buchstaben haben
			if (buchstabe > 12) {
			    return fehler;
			}
			// es könnte immer noch der Wortanfang sein
			wortAnfang = false;
			// wenn es nicht das erste Zeichen ist, wird untersucht, ob nicht unerlaubte Zeichen
			// davor stehen, also andere als '(' oder '"'
			if (z > 0) {
			    if (welchSonder(wort[z-1]) > 2) {
				return fehler;
			    }
			}
			// wenn wir schon mindestens drei Zeichen in dem Wort haben
			// wird untersucht, ob der gleiche Kleinbuchstabe nicht drei mal hintereinander steht
			if (z > 1) {
			    if (wort[z-2] == wort[z-1] && wort[z-1] == zeichen) {
				return fehler;
			    }
			}
		    } // Ende Kleinbuchstabe
		}// Ende Buchstaben

		// Sonderzeichen
		if (zeichen == '(') {
		    // eine öffnende Klammer nur am Wortanfang und nur, wenn keine Klammer schon offen ist
		    if (!wortAnfang || klammer) {
			return fehler;
		    } // wenn in Ordnung, wird die Klammer als geöffnet gesetzt
		    else {
			klammer = true;
		    }
		}// Ende '('

		if (zeichen == '\"') {
		    // wenn Anfuehrungsstrich noch nicht offen, darf er nur am Wortanfang stehen
		    if (!anfZeichen) {
			if (!wortAnfang) {
			    return fehler;
			} // sonst als geöffnet zu setzen
			else {
			    anfZeichen = true;
			}
		    }// Ende öffnend
		    // schliessend nicht am Wortanfang und es darf nur eins der Sonderzeichen '.,;' folgen
		    // (es wird überprüft, ob noch ein Zeichen folgt, um Überlauf zu vermeiden)
		    else {
			if (wortAnfang || ( z < wort.length-1 && welchSonder(wort[z+1]) < 4)) {
			    return fehler;
			} // sonst wird´s geschlossen
			else {
			    anfZeichen = false;
			}
		    }// Ende schliessend
		}// Ende '"'

		if (zeichen == ')') {
		    // schliessende Klammer darf nicht am Wortanfang stehen, muss schon offen sein
		    // und darf nur von den Zeichen '.,;' gefolgt werden
		    if (wortAnfang || !klammer || ( z < wort.length-1 && (wort[z+1]) < 4) ) {
			return fehler;
		    } // sonst wird Klammer geschlossen
		    else {
			klammer = false;
		    }
		}// Ende ')'

		if (zeichen == ';') {
		    //darf nur einmal vorkommen und muss am Wortende stehen
		    if (strichpunkt || ( z != wort.length-1 )) {
			return fehler;
		    } // sonst wird vorgemerkt, dass es schon vorkommt
		    else {
			strichpunkt = true;
		    }
		}// Ende ';'

		if (zeichen == ','){
		    // darf nur am Wortende vorkommen
		    if (z != wort.length-1) {
			return fehler;
		    }
		}// Ende ','

		if (zeichen == '.'){
		    // darf nur am Wortende vorkommen (das letzte Wort ergibt sich automatisch, da ja die Eingabe
		    // nach einem Punkt am Wortende abbricht)
		    if (z != wort.length-1) {
			return fehler;
		    }
		}// Ende '.'

	    }// Ende der wortSchleife, neuer Wortanfang erreicht
	    if (buchstabe == 0) {
		return fehler;
	    }

	    wortAnfang = true;
	    buchstabe = 0;
	} // Ende der satzSchleife
	// Überpruefen, ob Klammern & Anfuehrungszeichen nicht offen gelassen wurden
	if (klammer || anfZeichen) {
	    return fehler;
	}
	// dieser Punkt wird nur erreicht, wenn in dem Satz keine Fehler sind
	return "J";
    }// Ende der satzTesten - Methode
// ***************************************************************************************


    // diese Methode überprüft mit Hilfe der beiden nachfolgenden Methoden, ob das eingegeben Zeichen
    // ein Buchstabe ist und gibt true für Buchstaben und false für alle anderen Zeichen aus
    private static boolean istBuchstabe(char c){
	return (istKl(c) || istGr(c));
    } // Ende istBuchstabe - Methode
// ****************************************************************************************


    // diese Methode ueberprueft, ob der character ein Kleinbuchstabe ist und gibt dann
    // ein true zurück, sonst false
    private static boolean istKl(char c) {
	if ('a' <= c && c <= 'z') {
	    return true;
	}
	else {
	    return false;
	}
    } // Ende istKl - Methode
// ****************************************************************************************

    // diese Methode ueberprueft, ob der character ein Grossbuchstabe ist und gibt dann
    // ein true zurück sonst false
    private static boolean istGr(char c) {
	if ('A' <= c && c <= 'Z') {
	    return true;
	}
	else {
	    return false;
	}
    } // Ende istGr - Methode
// *****************************************************************************************

    // Diese Methode gibt den code des uebergebenen Sonderzeichens an, laut der hier
    // verwendeten kleinen Liste, oder -1 fuer keins der erlaubten Sonderzeichen
    // (Rückgabewert der String.indexOf(char c) Methode)
    private static int welchSonder(char c) {
	String sonderzeichen = " (\"),;.";
	return sonderzeichen.indexOf(c);
    } // Ende welchSonder - Methode

} // Ende der Satz - Klasse