diff --git a/pom.xml b/pom.xml index 680b9ad5b923a384115bb376c477879ec0abd7d2..00cb5b1fa8a05d0223c1cd099fac042158a1340f 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,12 @@ <version>4.12</version> <scope>test</scope> </dependency> + <!-- https://mvnrepository.com/artifact/org.controlsfx/controlsfx --> + <dependency> + <groupId>org.controlsfx</groupId> + <artifactId>controlsfx</artifactId> + <version>11.0.0</version> + </dependency> </dependencies> <build> <plugins> diff --git a/src/main/java/projekt/enigma/App.java b/src/main/java/projekt/enigma/App.java index 2e97208367f7280086e9b398514f64729c03c610..03f9260b62accc6a2544ef476fa58c3fb9082b91 100644 --- a/src/main/java/projekt/enigma/App.java +++ b/src/main/java/projekt/enigma/App.java @@ -1,15 +1,12 @@ package projekt.enigma; import javafx.application.Application; -import javafx.event.EventHandler; import javafx.fxml.FXMLLoader; -import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; import javafx.scene.layout.VBox; import javafx.stage.Stage; import projekt.enigma.model.Fehler; @@ -25,85 +22,64 @@ public class App extends Application { private static String kenngruppe; private static GuiController gc; - private static int debug; - Scene sce1, sce2; - - private static Parent loadFXML(String fxml) throws IOException { - FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(fxml + ".fxml")); - Parent result = fxmlLoader.load(); - - if (fxml.equals("gui")) { - gc = fxmlLoader.getController(); - gc.setKenngruppe(kenngruppe); - } - - return result; - } + private static int debug; public static void main(String[] args) { - debug = 1; + debug = 1; launch(args); } - public static int getDebug() { - return debug; - } - - public static void setDebug(int debug) { - App.debug = debug; - } + public static int getDebug() { + return debug; + } - @Override + @Override public void start(Stage primaryStage) throws IOException { primaryStage.setTitle("Kenngruppenabfrage"); - //Scene 1 Label label1 = new Label("Bitte Kenngruppe eingeben!"); label1.setTranslateX(55); Label l1 = new Label(""); Label l2 = new Label(""); TextField tfield = new TextField(); Button button1 = new Button("Kenngruppe setzen!"); + VBox layout1 = new VBox(); - - VBox layout1 = new VBox(); - - tfield.setOnKeyPressed(e -> { - if (e.getCode() == KeyCode.ENTER) { - if(enter(tfield.getText())) { - kenngruppe = tfield.getText(); - - try { - primaryStage.setScene(new Scene(loadFXML("gui"), 962, 677)); - } catch (IOException ex) { - ex.printStackTrace(); - } - } else { - tfield.setStyle("-fx-background-color:#FF0000"); - tfield.setText("Fehlerhafte Kenngruppe!"); - } - } - }); + layout1.getChildren().addAll(label1, l1, tfield, l2, button1); + Scene sceKenngruppe = new Scene(layout1, 234, 137); + + FXMLLoader guiLoader = new FXMLLoader(App.class.getResource("gui.fxml")); + + Scene sceApp = new Scene(guiLoader.load(), 962, 677); + + tfield.setOnKeyPressed(e -> { + if (e.getCode() == KeyCode.ENTER) { + if (enter(tfield.getText())) { + gc = guiLoader.getController(); + gc.setKenngruppe(tfield.getText()); + primaryStage.setScene(sceApp); + } else { + tfield.setText(""); + new Fehler().showErrorDialog("error", "Kenngruppe falsch", + "Regeln für die Kenngruppe: 4-8 Zeichen sowie nur Buchstaben von A-Z."); + } + } + }); button1.setOnAction(e -> { - if(enter(tfield.getText())) { - try { - primaryStage.setScene(new Scene(loadFXML("gui"), 962, 677)); - } catch (IOException ex) { - ex.printStackTrace(); - } + if (enter(tfield.getText())) { + gc = guiLoader.getController(); + gc.setKenngruppe(tfield.getText()); + primaryStage.setScene(sceApp); } else { - tfield.setStyle("-fx-background-color:#FF0000"); - tfield.setText("Fehlerhafte Kenngruppe!"); + tfield.setText(""); + new Fehler().showErrorDialog("error", "Kenngruppe falsch", + "Regeln für die Kenngruppe: 4-8 Zeichen sowie Buchstaben von A-Z."); } - }); + }); - layout1.getChildren().addAll(label1, l1, tfield, l2, button1); - - sce1 = new Scene(layout1, 234, 137); - - primaryStage.setScene(sce1); + primaryStage.setScene(sceKenngruppe); primaryStage.show(); } @@ -112,20 +88,19 @@ public class App extends Application { String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; boolean result = true; - for (char c :kenngruppe.toUpperCase().toCharArray()) { + for (char c : kenngruppe.toUpperCase().toCharArray()) { if (!alphabet.contains(String.valueOf(c))) { result = false; break; } } - if (kenngruppe.length() >= 9) { + if (kenngruppe.length() > 8 || kenngruppe.length() < 4) { result = false; } return result; } - // /** // * TODO Dokumentieren // */ diff --git a/src/main/java/projekt/enigma/GuiController.java b/src/main/java/projekt/enigma/GuiController.java index 6c73b6e4dc8abafb19363c0eb20e27c5fdac6df6..024e2aa1a5327278b7f1daa5dac52e6c8d17762c 100644 --- a/src/main/java/projekt/enigma/GuiController.java +++ b/src/main/java/projekt/enigma/GuiController.java @@ -1,15 +1,28 @@ package projekt.enigma; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.concurrent.Task; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.*; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.MenuItem; +import javafx.scene.control.TextField; import javafx.scene.input.MouseEvent; +import javafx.scene.layout.GridPane; import javafx.scene.shape.Circle; +import javafx.stage.StageStyle; import org.apache.http.HttpException; +import org.controlsfx.control.CheckComboBox; +import org.controlsfx.dialog.ProgressDialog; import projekt.enigma.model.Codierer; +import projekt.enigma.model.Fehler; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; public class GuiController { @@ -23,6 +36,7 @@ public class GuiController { private boolean resetDisplay; private Codierer codierer; private char chiffrierterBuchstabe; + private String[] empfangeneNachricht; //deklariert die benötigten Textfelder @FXML private TextField tfStecker1, tfStecker2, tfStecker3, tfStecker4, tfStecker5, tfStecker6, tfStecker7, tfStecker8, @@ -52,9 +66,15 @@ public class GuiController { private MenuButton mBtnWalzPos1, mBtnWalzPos2, mBtnWalzPos3, mBtnNotchPos1, mBtnNotchPos2, mBtnNotchPos3, mBtnStartPos1, mBtnStartPos2, mBtnStartPos3; + @FXML + private GridPane mainGrid; + + private static final String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + //endregion //region Init + /** * Initialisiert die Elemente GUI und setzt deren Startwerte */ @@ -82,6 +102,57 @@ public class GuiController { menu(mBtnStartPos2, position); } + /** + * Für das Steckbrett müssen zehn CheckComboBoxen erstellt werden. + * Hier wird die Funktion zum erstellen und Befüllen der Boxen, die Funktion zehn mal aufgerufen. + */ + private void generateSteckbrett() { + + for (int i = 0; i <= 9; i++) { + this.createSteckbrettPort(i); + } + } + + /** + * Die Funktion createSteckbrettPort erstellt zehn CheckComboBoxen, holt sich die verfügbaren Buchstaben, + * die bereits gesteckten Kabel und weißt sie zu. + * Im Anschluss werden die CheckComboBoxen auf dem GridPane positioniert. + * + * @param port : int : Kabel Nummer (0-9) + */ + private void createSteckbrettPort(int port) { + + // Item Liste anlegen + ObservableList<Character> items = FXCollections.observableArrayList(); + + // Holt die verfügbaren Buchstaben für diesen Port ab und erstellt ein char Array daraus + char[] verfuegbareBuchstaben = this.codierer.fetchVerfuegbareBuchstaben(port).toCharArray(); + + // Sortiert das Array nach dem Alphabet + Arrays.sort(verfuegbareBuchstaben); + + StringBuilder sb = new StringBuilder(); + + /** + * Die Buchstaben in die CheckComboBox laden und zusätzlich in einen String um später den + * Index des Buchstaben auslesen zu können + */ + for (char c : verfuegbareBuchstaben) { + items.add(c); + sb.append(c); + } + + // Eine CheckComboBox erstellen + CheckComboBox<Character> ccb = new CheckComboBox<Character>(items); + + // Die CheckComboBox dem GridPane in der Oberfläche zuordnen + mainGrid.add(ccb, 1 + port, 8); + + // Die Gesteckten Buchstaben in der CheckComboBox selektieren + ccb.getCheckModel().check(sb.toString().indexOf(this.codierer.fetchSteckverbindungen()[port][0])); + ccb.getCheckModel().check(sb.toString().indexOf(this.codierer.fetchSteckverbindungen()[port][1])); + } + /** * init Methode zur Erstellung der Einträge und Action Listener für die einzelnen Menüs * @@ -100,7 +171,7 @@ public class GuiController { mItem.get(i).setOnAction(e -> setMenuBtnText(button, finalMi.get(finalI))); } } - //endregion + //endregion //region EventHandler/Listener @@ -266,7 +337,14 @@ public class GuiController { */ @FXML private void gedrueckteTaste(ActionEvent e) { - if (e.getSource() == btnSenden && !tfCodiert.getText().equals("")) sendeFunkspruch(); + if (e.getSource() == btnSenden) { + if (tfCodiert.getText().equals("")) { + new Fehler().showErrorDialog("warning", "Haben Sie heute nichts zu sagen?", + "Nutzung von militärischer Infrastruktur ohne Grund ist verboten."); + } else { + sendeFunkspruch(); + } + } if (e.getSource() == btnEmpfangen) empfangeFunkspruch(); if (e.getSource() == btnDelete) loeschen(); if (e.getSource() == btnReset) { @@ -275,9 +353,10 @@ public class GuiController { this.setzeTagesSchluessel(); } } - //endregion + //endregion //region Methoden + /** * Setzt die Hintergrundfarbe des Kreises (chiffrierter Buchstabe) auf gelb bzw. auf grau. * @@ -423,16 +502,23 @@ public class GuiController { */ private void empfangeFunkspruch() { - String[] empfangeneNachricht = codierer.empfangeNachricht(); + progressDialogue("rx"); - if (empfangeneNachricht[2] != null) { - setzeTagesSchluessel(); - tfKlartext.setText(empfangeneNachricht[2]); - tfCodiert.setText(empfangeneNachricht[1]); - resetDisplay = true; + try { + if (this.empfangeneNachricht[2] != null && this.empfangeneNachricht[1] != null) { + setzeTagesSchluessel(); + tfKlartext.setText(this.empfangeneNachricht[2]); + tfCodiert.setText(this.empfangeneNachricht[1]); + resetDisplay = true; - // Spruchschluessel in das Feld lblSpruchschluessel schreiben - lblSpruchschluessel.setText(codierer.empfangenerSpruchschluessel(empfangeneNachricht[2])); + // Spruchschluessel in das Feld lblSpruchschluessel schreiben + lblSpruchschluessel.setText(codierer.empfangenerSpruchschluessel(this.empfangeneNachricht[2])); + } + } catch (NullPointerException ignored) { + new Fehler().showErrorDialog( + "warning", + "Keiner schreibt dir...", + "Es liegen keine neuen Nachrichten im Funkraum für Sie vor."); } } @@ -442,15 +528,50 @@ public class GuiController { */ private void sendeFunkspruch() { - this.tfKlartext.setText(""); + this.tfKlartext.setText(""); this.tfCodiert.setText(""); - try { - this.codierer.sendeNachricht(); - } catch (HttpException | IOException e) { - e.printStackTrace(); - } + progressDialogue("tx"); + } + + private void progressDialogue(String strRxTx) { + + Task copyWorker = createWorker(strRxTx); + + ProgressDialog dialog = new ProgressDialog(copyWorker); + dialog.initStyle(StageStyle.TRANSPARENT); + dialog.setGraphic(null); + dialog.initStyle(StageStyle.TRANSPARENT); + dialog.setTitle("Kommunikation zum Funkraum"); + if (strRxTx.equals("rx")) { + dialog.setContentText("Empfange Nachricht"); + } else if (strRxTx.equals("tx")) { + dialog.setContentText("Sende Nachricht"); + } + dialog.setHeaderText(null); + dialog.setGraphic(null); + dialog.initStyle(StageStyle.UTILITY); + new Thread(copyWorker).start(); + dialog.showAndWait(); + } + public Task createWorker(String strRxTx) { + return new Task() { + @Override + protected Object call() throws Exception { + if (strRxTx.equals("rx")) { + empfangeneNachricht = codierer.empfangeNachricht(); + } else if (strRxTx.equals("tx")) { + try { + codierer.sendeNachricht(); + } catch (HttpException | IOException e) { + e.printStackTrace(); + } + } + + return true; + } + }; } /** @@ -646,6 +767,11 @@ public class GuiController { mBtnStartPos3.setText(String.valueOf(codierer.fetchWalzen()[2])); // Steckbrett Felder setzen + + // Setzt das Steckbrett + generateSteckbrett(); + + /* tfStecker1.setText(codierer.fetchSteckverbindungen()[0][0] + "" + codierer.fetchSteckverbindungen()[0][1]); tfStecker2.setText(codierer.fetchSteckverbindungen()[1][0] + "" + @@ -665,7 +791,7 @@ public class GuiController { tfStecker9.setText(codierer.fetchSteckverbindungen()[8][0] + "" + codierer.fetchSteckverbindungen()[8][1]); tfStecker10.setText(codierer.fetchSteckverbindungen()[9][0] + "" + - codierer.fetchSteckverbindungen()[9][1]); + codierer.fetchSteckverbindungen()[9][1]);*/ this.textCodiert = ""; this.textEingabe = ""; this.tfKlartext.setText(""); @@ -676,17 +802,17 @@ public class GuiController { public void setKenngruppe(String kenngruppe) { - // Initialisieren des Codierers und setzen der Kenngruppe - codierer = new Codierer(kenngruppe); + // Initialisieren des Codierers und setzen der Kenngruppe + codierer = new Codierer(kenngruppe); - this.codierer.resetHardware(); + this.codierer.resetHardware(); - // Beim nächsten Tastendruck erstmal das Display löschen damit falschen Nachrichten geschickt werden. - resetDisplay = true; + // Beim nächsten Tastendruck erstmal das Display löschen damit falschen Nachrichten geschickt werden. + resetDisplay = true; - // Einstellungen aus dem Logbuch auslesen und setzen - setzeTagesSchluessel(); - setzeSteckverbindungen(); + // Einstellungen aus dem Logbuch auslesen und setzen + setzeTagesSchluessel(); + setzeSteckverbindungen(); } //endregion } diff --git a/src/main/java/projekt/enigma/model/Codierer.java b/src/main/java/projekt/enigma/model/Codierer.java index 136ab25a2e104eeeeb40f940d1950f7b3426ed71..ce401e31527f9a557c8b505c0ed3cc7b8b6a67c9 100644 --- a/src/main/java/projekt/enigma/model/Codierer.java +++ b/src/main/java/projekt/enigma/model/Codierer.java @@ -1,7 +1,6 @@ package projekt.enigma.model; import org.apache.http.HttpException; -import projekt.enigma.threads.ThreadFunkraum; import java.io.IOException; import java.util.Calendar; @@ -15,525 +14,530 @@ import java.util.Random; */ public class Codierer { - //region Variablen - /** - * Der Klartext Spruchschlüssel zur codierung der Nachricht - */ - private String spruchschluessel; - - /** - * Der Spruchschlüssel, mit den Tageswerten aus dem Codebuch, codiert - */ - private String spruchschluesselCodiert; - - /** - * Die Kenngruppe für die versendeten Nachrichten gedacht sind. Diese ist relevant für den Webservice (Funkraum) - */ - private String kenngruppe; - - /** - * Die Nachricht, welche der Benutzer eingibt, wird als String nachricht gespeichert - * und im laufe der Benutzung ergänzt - */ - private String nachricht; - - /** - * Das Hardware Objekt. Hier werden alle Hardware relevanten Baugruppen gespeichert und verarbeitet. - */ - private Hardware hardware; - - /** - * Im Codebuch sind die Tageswerte zu finden. Über dieses Objekt kann darauf zugegriffen werden. - */ - private Codebuch codebuch; - - //TODO Dokumentieren - private Thread funk; - //endregion - - //region Konstruktor - - /** - * Der Konstruktor des Codierers - * Hier werden die globalen Variablen auf ihre Standart Werte gesetzt sowie die Objekte Initialisiert. - */ - public Codierer(String kenngruppe) { - - this.nachricht = ""; - this.spruchschluessel = ""; - this.spruchschluesselCodiert = ""; - this.kenngruppe = kenngruppe; - - this.codebuch = new Codebuch(); - this.codebuch.fetchTagesschluessel(); - - /*this.funk = new Thread(new ThreadFunkraum(this.kenngruppe)); - funk.start();*/ - } - //endregion - - //region Funktionen & Methoden - - //region Reset & Initialisieren - /** - * Hier lesen wir den heutigen Eintrag aus dem Codebuch aus und erstellen ein Codebuch Objekt - * Nach dem Codebuch werden dann die Ringe auf die Walzen gesteckt und die Walzen anschließend - * in die Hardware gebaut. - * <br> - * Ein Reflektor wird definiert, jedoch keine Werte zugewisen, da wir nur einen besitzen und - * deshalb alle Einstellungen hierfür Statisch im Reflektor definiert haben. - * <br> - * Das Steck wird ebenfalls definiert und die notwendigen Kabel eingesteckt laut dem heutigen - * Codebuch Eintrag. - */ - private void initialisiereHardware() { - - this.nachricht = ""; - - // Das Steckbrett initialisieren - Steckbrett sb = new Steckbrett(); - char[][] verbinder = this.codebuch.getSteckverbindung(); - - // Für jedes Kabel eine Verbindung auf dem Steckbrett setzen - for (char[] kabel : verbinder) { - sb.setzeVertauschung(kabel[0], kabel[1]); - } - - // Die Hardware aus dem Koffer holen (initialisieren) - this.hardware = new Hardware(); - - // Den Ring an der Walze anbringen und die Walze dann in die Hardware einsetzen - this.hardware.setWalzen(0, this.codebuch.getWalzenlage()[0], this.codebuch.getRingstellung()[0]); - this.hardware.setWalzen(1, this.codebuch.getWalzenlage()[1], this.codebuch.getRingstellung()[1]); - this.hardware.setWalzen(2, this.codebuch.getWalzenlage()[2], this.codebuch.getRingstellung()[2]); - - // Der Hardware das gesetzte Steckbrett zuweisen - this.hardware.setSteckbrett(sb); - - // Ein Reflektor Objekt erstellen und der Hardware bekannt geben - this.hardware.setReflektor(new Reflektor()); - } - - /** - * Setzt die Enigma auf die Einstellungen des aktuellen Tages, aus dem Codebuch zurück. - */ - public void resetHardware() { - this.initialisiereHardware(); - } - - /** - * Leer das Nachrichten Objekt um eine neue Nachricht aufnehmen zu können - */ - public void resetNachricht() { - this.nachricht = ""; - } - //endregion - - //region Nachrichten handler - - /** - * Befehl die Nachricht an den Funker zu übergeben - * - * @throws IOException : Die Antwort konnte nicht gelesen werden - * @throws HttpException : Die Nachricht konnte nicht abgesendet werden - */ - public void sendeNachricht() throws IOException, HttpException { - String kopf = this.generateKopf(); - new Funkraum().sendeFunkspruch(new Morsecode().convertBuchstabeToMorsecode(kopf + this.nachricht), this.kenngruppe); - this.nachricht = ""; - this.resetHardware(); - } - - /** - * Gibt die letzte empfangene Nachricht zurück - * <br> - * String[0] Tag wann die Nachricht gesendet wurde - * String[1] = Die verschlüsselte Nachricht - * String[2] = Nachricht im Klartext - */ - public String[] empfangeNachricht() { - - // Alte Nachrichten Variable erstmal leeren - this.nachricht = ""; - // Morsecode Objekt initialisieren - Morsecode mc = new Morsecode(); - // Unser Nachrichten Array soll drei Einträge erhalten - String[] nachricht = new String[4]; - // Abrufen der letzten Nachricht, für unsere Kenngruppe, aus dem Funkraum - String[] codierteNachricht = new Funkraum().empfangeFunkspruch(this.kenngruppe); - - new Fehler().debug(String.valueOf(codierteNachricht.length), false); - new Fehler().debug(codierteNachricht[0], false); - new Fehler().debug(codierteNachricht[1], false); - - // Prüfen ob Nachrichtenlänge > 1 und die codierte Nachricht mehr als drei Felder (" ") hat - if (codierteNachricht[1] != null && codierteNachricht[1].split(" ").length > 3) { - // Den Tag der Nachricht speichern - nachricht[0] = codierteNachricht[0]; - // Die Nachricht von Morsecode in Buchstaben konvertieren - nachricht[1] = mc.convertMorsecodeToBuchstabe(codierteNachricht[1]); - // Die Enigma Nachricht (nachricht[1]) mittels der Tageseinstellungen (nachricht[0]) decodieren - nachricht[2] = this.decodiere(nachricht[1], Integer.parseInt(nachricht[0])); - // StringBuilder initialisieren - StringBuilder sb = new StringBuilder(); - - sb.append(nachricht[1], 0, 16); - for (int i = 17; i <= nachricht[1].length(); ) { - if ((i + 5) < nachricht[1].length()) { - sb.append(nachricht[1], i, i + 5).append(" "); - i += 5; - } else { - sb.append(nachricht[1].substring(i)); - break; - } - } - nachricht[1] = sb.toString(); - } - - return nachricht; - } - //endregion - - //region Generatoren - - /** - * Hier wird ein neuer Spruchschlüssel generiert. - * <p> - * Mit diesem werden die Walzen auf eine neue Startposition gestellt und dem Kopf, mit dem - * Tagesschlüssel codiert, hinzugefügt. - * <br> - * Hierfür wird mittels der Funktion "randomBuchstabe" ein zufälliger Buchstabe generiert, - * und geschaut ob dieser bereits in der globalen Variable (this.spruchschluessel) vorhanden ist. - * Wenn nicht, wird der Buchstabe dem Spruchschlüssel hinzugefügt. - * <br> - * Dies wir nun so lange gemacht bis der Spruchschlüssel eine länge von drei Zeichen hat. - */ - public void generateSpruchschluessel() { - - String klartext = ""; - - while (klartext.length() < 3) { - String temp = this.randomBuchstabe(); - if (!klartext.contains(temp)) { - klartext += temp; - } - } - - this.spruchschluessel = klartext; - this.spruchschluesselCodiert = this.codiere(klartext + klartext, false); - - // Walzen auf den Spruchschlüssel stellen - this.hardware.setzePosition(0, this.spruchschluessel.charAt(0)); - this.hardware.setzePosition(1, this.spruchschluessel.charAt(1)); - this.hardware.setzePosition(2, this.spruchschluessel.charAt(2)); - - // Die Kenngruppe codieren und in der Nachricht speichern - this.codiere(this.kenngruppe, true); - } - - /** - * Erstellen des Nachrichten Kopfes. - * Hierfür wird die aktuelle Uhrzeit ausgelesen, die Länge der Nachricht sowie der, mit den - * Tagescodes codierte, Spruchschlüssel. - */ - private String generateKopf() { - Calendar cal = Calendar.getInstance(); - - // Uhrzeit an den Kopf hängen - return String.format("%02d%02d", cal.get(Calendar.HOUR), cal.get(Calendar.MINUTE)) + " " + - // Zeichen Anzahl der Nachricht - this.nachricht.length() + " " + - // Spruchschlüssel anhängen - this.spruchschluesselCodiert.substring(0, 3) + " " + this.spruchschluesselCodiert.substring(3, 6) + " "; - } - - /** - * Einen zufälligen Buchstaben aus dem Alphabet generieren. - * In der Funktion gibt es den String Alphabet, in welchem alle zulässigen Zeichen eingetragen sind. - * Aus diesem String wird nun zufällig ein Zeichen ausgewählt und zurück gegeben. - * - * @return String : ein zufällig generierter Buchstabe - */ - private String randomBuchstabe() { - return String.valueOf((char) ('A' + new Random().nextInt(26))); - } - //endregion - - //region setzte Funktionen - - /** - * Setzt den anzuzeigenden Buchstaben (buchstabe) auf der Walze (walzenPosition) und resetet anschließen das - * Nachrichten Objekt - * - * @param walzenPosition : int : Nummer der Walze - * @param buchstabe : char : Buchstabe der zugewiesen soll - */ - public void setzeWalze(int walzenPosition, char buchstabe) { - this.resetNachricht(); - this.hardware.setzePosition(walzenPosition, buchstabe); - } - - /** - * Setzt den Ring auf der Walze auf einen neuen Umstprungwert. - * - * @param walzenPosition : int : Walze auf die der Ring gesteckt wird - * @param umsprungPunkt : int : Buchstabe auf dem der Notch sitzt - */ - public void setzeRing(int walzenPosition, int umsprungPunkt) { - this.hardware.setzeRing(walzenPosition, umsprungPunkt); - } - - /** - * Setzt die Walze (walzeNr) in die Position (walzenPosition) der Enigma ein. - * Mit (ringstellung) gibt man die Position des Umsprungpunktes an. - * - * @param walzenPosition : int : Position der Walze in der Enigma (1-2-3) - * @param walzeNr : int : Nummer der Walze die eingesetzt wird - * @param ringstellung : int : Stellung des Ringes - */ - public void setzeWalzeNr(int walzenPosition, int walzeNr, int ringstellung) { - this.hardware.setzeWalzenNr(walzenPosition, walzeNr, ringstellung); - } - - /** - * Setzt das Kabel in beide Ports ein und fügt es dem Steckbrett Array hinzu. - * - * @param port : int : Kabel Nummer welches am Steckbrett eingesteckt wird - * @param verbindung : String : Verbindung welche die vertauschten Buchstaben angibt - * @return boolean : Wenn true, darf das Kabel gesteckt werden, wenn nicht, steckt da bereits schon eines - */ - public boolean setzeSteckbrett(int port, String verbindung) { - return this.hardware.getSteckbrett().setzeVertauschung(port, verbindung.charAt(0), verbindung.charAt(1)); - } - //endregion - - //region fetch Funktionen - - /** - * Gibt die Ringstellungen aus dem Codebuch zurück - * - * @return int[] : Array mit den Ringstellungen der drei eingesetzten Walzen - */ - public int[] fetchRingstellung() { - return this.codebuch.getRingstellung(); - } - - /** - * Gibt die Walzennummer aus dem Codebuch zurück - * - * @return int[] : Array mit den Nummern der drei eingesetzten Walzen - */ - public int[] fetchWalzenNr() { - return this.codebuch.getWalzenlage(); - } - - /** - * Gibt die Steckverbindungen aus dem Codebuch zurück - * - * @return char[][] : Array mit den gesteckten Verbindungen im Steckbrett - */ - public char[][] fetchSteckverbindungen() { - return this.codebuch.getSteckverbindung(); - } - - /** - * Gibt die aktuellen Buchstaben auf den Walzen zurück - * - * @return char[] : Walzen Array mit der aktuellen Position - */ - public char[] fetchWalzen() { - char[] walzen = new char[3]; - walzen[0] = this.hardware.getWalzen()[0].getPosition(); - walzen[1] = this.hardware.getWalzen()[1].getPosition(); - walzen[2] = this.hardware.getWalzen()[2].getPosition(); - - return walzen; - } - //endregion - - //region codierer - - /** - * Hier wird ein einzelner Buchstabe verschlüsselt. - * Man muss hier ebenfalls mitgeben ob der codierte String in Codierer.nachricht gespeichert werden soll oder nicht. - * In der Regel ist dies der Fall. - * - * @param buchstabe : char : Der zu codierende Buchstabe - * @param save : boolean : Nachricht speichern oder nicht - * @return char : Der codierte Buchstabe - */ - public char codiere(char buchstabe, boolean save) { - - char codiert = this.hardware.codiere(buchstabe); - - if (save) { - this.nachricht += codiert; - } - - return codiert; - } - - /** - * Codiert den Übergebenen String. - * Man muss hier ebenfalls mitgeben ob der codierte String in Codierer.nachricht gespeichert werden soll oder nicht. - * In der Regel ist dies der Fall. - * - * @param klartext : String : Der zu codierende Text - * @param save : boolean : Nachricht speichern oder nicht - * @return String : Der codierte Text zusätzlich als Rückgabe - */ - public String codiere(String klartext, boolean save) { - - StringBuilder sb = new StringBuilder(); - - for (char buchstabe : klartext.toCharArray()) { - sb.append(this.codiere(buchstabe, save)); - } - - return sb.toString(); - } - - /** - * Diese Funktion erwartet als (codierteNachricht) eine korrekte Enigma Nachricht. - * Ihr muss auch der Tag der codierung mitgegeben werden. Dieser weiß dein Funker im Funkraum. - * In der Regel ist dies der Tag des Nachrichten empfangs. - * - * @param codierteNachricht : String : Enigma codierte Nachricht - * @param tag : int : Tag der Nachricht - * @return String : decodierte Nachricht - */ - private String decodiere(String codierteNachricht, int tag) { - - // Hardware reseten und Tageseinstellungen aus dem Codebuch laden - this.codebuch.fetchTagesschluessel(tag); - this.initialisiereHardware(); - - // Nachricht splitten mit whitespace als delimiter - String[] nachricht = codierteNachricht.split(" "); - StringBuilder sb = new StringBuilder(); - - // Uhrzeit - sb.append(nachricht[0]).append(" "); - - // Zeichen Anzahl der Nachricht - sb.append(nachricht[1]).append(" "); - - // Spruchschlüssel - String spruchschluessel = this.decodiereString(nachricht[2]); - - sb.append(spruchschluessel).append(" "); - sb.append(this.decodiereString(nachricht[3])).append(" "); - - // Walzen neu einstellen mit dem Spruchschlüssel - this.hardware.setzePosition(0, spruchschluessel.charAt(0)); - this.hardware.setzePosition(1, spruchschluessel.charAt(1)); - this.hardware.setzePosition(2, spruchschluessel.charAt(2)); - - // Nachricht decodieren - sb.append(this.decodiereString(nachricht[4])); - - return sb.toString(); - } - - /** - * Zerlegt den übergebenen String in einen char Array und decodiert jedes Zeichen. - * Der String wird dann decodiert zurück gegeben. - * - * @param nachricht : String : Der zu decodierende Text - * @return String : Der decodierte Text - */ - private String decodiereString(String nachricht) { - - StringBuilder sb = new StringBuilder(); - - for (char buchstabe : nachricht.toCharArray()) { - if (buchstabe > 0) { - sb.append(this.hardware.codiere(buchstabe)); - } - } - - return sb.toString(); - } - //endregion - - //region Sonstige - - /** - * Prüft ob der Port auf den das Kabel gesteckt werden soll, noch frei ist. - * <p> - * setSteckbrett ausführen mit beiden Buchstaben als String - * - * @param buchstabe : char : Der zuletzt eingegebene Buchstabe - * @return boolean : Wenn der Buchstabe nicht vorhanden ist, wird true zurückgegeben, ansonsten false - */ - public boolean pruefeSteckbrettPort(char buchstabe) { - return this.hardware.getSteckbrett().ueberpruefeVertauschungen(buchstabe); - } - - /** - * Ließt aus der empfangenen Nachricht den Spruchschlüssel aus und gibt ihn zurück. - * - * @param empfangeneNachricht : String : Die empfangene Nachricht als String - * @return String : Der Spruchschlüssel mit welcher die Nachricht codiert wurde. - */ - public String empfangenerSpruchschluessel(String empfangeneNachricht) { - String[] nachricht = empfangeneNachricht.split(" "); - - return nachricht[2]; - } - - /** - * Löscht das letzte Zeichen aus der Nachricht und dreht die Walzen eine Position zurück. - */ - public void letztesZeichenLoeschen() { - this.hardware.dreheWalzen(-1); - this.nachricht = this.nachricht.substring(0, this.nachricht.length() - 1); - } - //endregion - //endregion - - //region Setter - /** - * Setzt die Kenngruppe welche die Enigma gerade benutzt. - * - * @param kenngruppe : String : Kenngruppe welche die Enigma gerade benutzt - */ - public void setKenngruppe(String kenngruppe) { - - this.kenngruppe = kenngruppe; - this.initialisiereHardware(); - } - //endregion - - //region Getter - - /** - * Liest die Kenngruppe aus welche die Maschine gerade besitzt. Früher war dies eine eindeutige Nummer - * die einer Einheit zugewiesen war. Wir hinterlegen hier einen Benutzernamen. - * - * @return String : Kenngruppe - */ - public String getKenngruppe() { - return kenngruppe; - } - - /** - * Der Spruchschlüssel wird, zur internen Verwendung, auch im Klartext gespeichert. - * Wir brauchen diesen dann zum codieren der eigentlichen Nachricht. - * - * @return String : Der klartext Spruchschlüssel - */ - public String getSpruchschluessel() { - return this.spruchschluessel; - } - - /** - * Gibt die bisher erstellte Nachricht zurück - * - * @return String : Erstellte Nachricht - */ - public String getNachricht() { - return nachricht; - } - //endregion + //region Variablen + /** + * Der Klartext Spruchschlüssel zur codierung der Nachricht + */ + private String spruchschluessel; + + /** + * Der Spruchschlüssel, mit den Tageswerten aus dem Codebuch, codiert + */ + private String spruchschluesselCodiert; + + /** + * Die Kenngruppe für die versendeten Nachrichten gedacht sind. Diese ist relevant für den Webservice (Funkraum) + */ + private String kenngruppe; + + /** + * Die Nachricht, welche der Benutzer eingibt, wird als String nachricht gespeichert + * und im laufe der Benutzung ergänzt + */ + private String nachricht; + + /** + * Das Hardware Objekt. Hier werden alle Hardware relevanten Baugruppen gespeichert und verarbeitet. + */ + private Hardware hardware; + + /** + * Im Codebuch sind die Tageswerte zu finden. Über dieses Objekt kann darauf zugegriffen werden. + */ + private Codebuch codebuch; + + //TODO Dokumentieren + private Thread funk; + //endregion + + //region Konstruktor + + /** + * Der Konstruktor des Codierers + * Hier werden die globalen Variablen auf ihre Standart Werte gesetzt sowie die Objekte Initialisiert. + */ + public Codierer(String kenngruppe) { + + this.nachricht = ""; + this.spruchschluessel = ""; + this.spruchschluesselCodiert = ""; + this.kenngruppe = kenngruppe; + + this.codebuch = new Codebuch(); + this.codebuch.fetchTagesschluessel(); + } + //endregion + + //region Funktionen & Methoden + + //region Reset & Initialisieren + + /** + * Hier lesen wir den heutigen Eintrag aus dem Codebuch aus und erstellen ein Codebuch Objekt + * Nach dem Codebuch werden dann die Ringe auf die Walzen gesteckt und die Walzen anschließend + * in die Hardware gebaut. + * <br> + * Ein Reflektor wird definiert, jedoch keine Werte zugewisen, da wir nur einen besitzen und + * deshalb alle Einstellungen hierfür Statisch im Reflektor definiert haben. + * <br> + * Das Steck wird ebenfalls definiert und die notwendigen Kabel eingesteckt laut dem heutigen + * Codebuch Eintrag. + */ + private void initialisiereHardware() { + + this.nachricht = ""; + + // Das Steckbrett initialisieren + Steckbrett sb = new Steckbrett(); + char[][] verbinder = this.codebuch.getSteckverbindung(); + + // Für jedes Kabel eine Verbindung auf dem Steckbrett setzen + for (char[] kabel : verbinder) { + sb.setzeVertauschung(kabel[0], kabel[1]); + } + + // Die Hardware aus dem Koffer holen (initialisieren) + this.hardware = new Hardware(); + + // Den Ring an der Walze anbringen und die Walze dann in die Hardware einsetzen + this.hardware.setWalzen(0, this.codebuch.getWalzenlage()[0], this.codebuch.getRingstellung()[0]); + this.hardware.setWalzen(1, this.codebuch.getWalzenlage()[1], this.codebuch.getRingstellung()[1]); + this.hardware.setWalzen(2, this.codebuch.getWalzenlage()[2], this.codebuch.getRingstellung()[2]); + + // Der Hardware das gesetzte Steckbrett zuweisen + this.hardware.setSteckbrett(sb); + + // Ein Reflektor Objekt erstellen und der Hardware bekannt geben + this.hardware.setReflektor(new Reflektor()); + } + + /** + * Setzt die Enigma auf die Einstellungen des aktuellen Tages, aus dem Codebuch zurück. + */ + public void resetHardware() { + this.initialisiereHardware(); + } + + /** + * Leer das Nachrichten Objekt um eine neue Nachricht aufnehmen zu können + */ + public void resetNachricht() { + this.nachricht = ""; + } + //endregion + + //region Nachrichten handler + + /** + * Befehl die Nachricht an den Funker zu übergeben + * + * @throws IOException : Die Antwort konnte nicht gelesen werden + * @throws HttpException : Die Nachricht konnte nicht abgesendet werden + */ + public void sendeNachricht() throws IOException, HttpException { + String kopf = this.generateKopf(); + new Funkraum().sendeFunkspruch(new Morsecode().convertBuchstabeToMorsecode(kopf + this.nachricht), this.kenngruppe); + this.nachricht = ""; + this.resetHardware(); + } + + /** + * Gibt die letzte empfangene Nachricht zurück + * <br> + * String[0] Tag wann die Nachricht gesendet wurde + * String[1] = Die verschlüsselte Nachricht + * String[2] = Nachricht im Klartext + */ + public String[] empfangeNachricht() { + + // Alte Nachrichten Variable erstmal leeren + this.nachricht = ""; + // Morsecode Objekt initialisieren + Morsecode mc = new Morsecode(); + // Unser Nachrichten Array soll drei Einträge erhalten + String[] nachricht = new String[4]; + // Abrufen der letzten Nachricht, für unsere Kenngruppe, aus dem Funkraum + String[] codierteNachricht = new Funkraum().empfangeFunkspruch(this.kenngruppe); + + // Prüfen ob Nachrichtenlänge > 1 und die codierte Nachricht mehr als drei Felder (" ") hat + if (codierteNachricht[1] != null && codierteNachricht[1].split(" ").length > 3) { + // Den Tag der Nachricht speichern + nachricht[0] = codierteNachricht[0]; + // Die Nachricht von Morsecode in Buchstaben konvertieren + nachricht[1] = mc.convertMorsecodeToBuchstabe(codierteNachricht[1]); + // Die Enigma Nachricht (nachricht[1]) mittels der Tageseinstellungen (nachricht[0]) decodieren + nachricht[2] = this.decodiere(nachricht[1], Integer.parseInt(nachricht[0])); + // StringBuilder initialisieren + StringBuilder sb = new StringBuilder(); + + sb.append(nachricht[1], 0, 16); + for (int i = 17; i <= nachricht[1].length(); ) { + if ((i + 5) < nachricht[1].length()) { + sb.append(nachricht[1], i, i + 5).append(" "); + i += 5; + } else { + sb.append(nachricht[1].substring(i)); + break; + } + } + nachricht[1] = sb.toString(); + } + + return nachricht; + } + //endregion + + //region Generatoren + + /** + * Hier wird ein neuer Spruchschlüssel generiert. + * <p> + * Mit diesem werden die Walzen auf eine neue Startposition gestellt und dem Kopf, mit dem + * Tagesschlüssel codiert, hinzugefügt. + * <br> + * Hierfür wird mittels der Funktion "randomBuchstabe" ein zufälliger Buchstabe generiert, + * und geschaut ob dieser bereits in der globalen Variable (this.spruchschluessel) vorhanden ist. + * Wenn nicht, wird der Buchstabe dem Spruchschlüssel hinzugefügt. + * <br> + * Dies wir nun so lange gemacht bis der Spruchschlüssel eine länge von drei Zeichen hat. + */ + public void generateSpruchschluessel() { + + String klartext = ""; + + while (klartext.length() < 3) { + String temp = this.randomBuchstabe(); + if (!klartext.contains(temp)) { + klartext += temp; + } + } + + this.spruchschluessel = klartext; + this.spruchschluesselCodiert = this.codiere(klartext + klartext, false); + + // Walzen auf den Spruchschlüssel stellen + this.hardware.setzePosition(0, this.spruchschluessel.charAt(0)); + this.hardware.setzePosition(1, this.spruchschluessel.charAt(1)); + this.hardware.setzePosition(2, this.spruchschluessel.charAt(2)); + + // Die Kenngruppe codieren und in der Nachricht speichern + this.codiere(this.kenngruppe, true); + } + + /** + * Erstellen des Nachrichten Kopfes. + * Hierfür wird die aktuelle Uhrzeit ausgelesen, die Länge der Nachricht sowie der, mit den + * Tagescodes codierte, Spruchschlüssel. + */ + private String generateKopf() { + Calendar cal = Calendar.getInstance(); + + // Uhrzeit an den Kopf hängen + return String.format("%02d%02d", cal.get(Calendar.HOUR), cal.get(Calendar.MINUTE)) + " " + + // Zeichen Anzahl der Nachricht + this.nachricht.length() + " " + + // Spruchschlüssel anhängen + this.spruchschluesselCodiert.substring(0, 3) + " " + this.spruchschluesselCodiert.substring(3, 6) + " "; + } + + /** + * Einen zufälligen Buchstaben aus dem Alphabet generieren. + * In der Funktion gibt es den String Alphabet, in welchem alle zulässigen Zeichen eingetragen sind. + * Aus diesem String wird nun zufällig ein Zeichen ausgewählt und zurück gegeben. + * + * @return String : ein zufällig generierter Buchstabe + */ + private String randomBuchstabe() { + return String.valueOf((char) ('A' + new Random().nextInt(26))); + } + //endregion + + //region setzte Funktionen + + /** + * Setzt den anzuzeigenden Buchstaben (buchstabe) auf der Walze (walzenPosition) und resetet anschließen das + * Nachrichten Objekt + * + * @param walzenPosition : int : Nummer der Walze + * @param buchstabe : char : Buchstabe der zugewiesen soll + */ + public void setzeWalze(int walzenPosition, char buchstabe) { + this.resetNachricht(); + this.hardware.setzePosition(walzenPosition, buchstabe); + } + + /** + * Setzt den Ring auf der Walze auf einen neuen Umstprungwert. + * + * @param walzenPosition : int : Walze auf die der Ring gesteckt wird + * @param umsprungPunkt : int : Buchstabe auf dem der Notch sitzt + */ + public void setzeRing(int walzenPosition, int umsprungPunkt) { + this.hardware.setzeRing(walzenPosition, umsprungPunkt); + } + + /** + * Setzt die Walze (walzeNr) in die Position (walzenPosition) der Enigma ein. + * Mit (ringstellung) gibt man die Position des Umsprungpunktes an. + * + * @param walzenPosition : int : Position der Walze in der Enigma (1-2-3) + * @param walzeNr : int : Nummer der Walze die eingesetzt wird + * @param ringstellung : int : Stellung des Ringes + */ + public void setzeWalzeNr(int walzenPosition, int walzeNr, int ringstellung) { + this.hardware.setzeWalzenNr(walzenPosition, walzeNr, ringstellung); + } + + /** + * Setzt das Kabel in beide Ports ein und fügt es dem Steckbrett Array hinzu. + * + * @param port : int : Kabel Nummer welches am Steckbrett eingesteckt wird + * @param verbindung : String : Verbindung welche die vertauschten Buchstaben angibt + * @return boolean : Wenn true, darf das Kabel gesteckt werden, wenn nicht, steckt da bereits schon eines + */ + public boolean setzeSteckbrett(int port, String verbindung) { + return this.hardware.getSteckbrett().setzeVertauschung(port, verbindung.charAt(0), verbindung.charAt(1)); + } + //endregion + + //region fetch Funktionen + + /** + * Gibt die Ringstellungen aus dem Codebuch zurück + * + * @return int[] : Array mit den Ringstellungen der drei eingesetzten Walzen + */ + public int[] fetchRingstellung() { + return this.codebuch.getRingstellung(); + } + + /** + * Gibt die Walzennummer aus dem Codebuch zurück + * + * @return int[] : Array mit den Nummern der drei eingesetzten Walzen + */ + public int[] fetchWalzenNr() { + return this.codebuch.getWalzenlage(); + } + + /** + * Gibt die Steckverbindungen aus dem Codebuch zurück + * + * @return char[][] : Array mit den gesteckten Verbindungen im Steckbrett + */ + public char[][] fetchSteckverbindungen() { + return this.codebuch.getSteckverbindung(); + } + + /** + * Gibt die aktuellen Buchstaben auf den Walzen zurück + * + * @return char[] : Walzen Array mit der aktuellen Position + */ + public char[] fetchWalzen() { + char[] walzen = new char[3]; + walzen[0] = this.hardware.getWalzen()[0].getPosition(); + walzen[1] = this.hardware.getWalzen()[1].getPosition(); + walzen[2] = this.hardware.getWalzen()[2].getPosition(); + + return walzen; + } + + /** + * TODO: Doku + * + * @param port + * @return + */ + public String fetchVerfuegbareBuchstaben(int port) { + return this.hardware.getSteckbrett().fetchVerfuegbareBuchstaben(port); + } + //endregion + + //region codierer + + /** + * Hier wird ein einzelner Buchstabe verschlüsselt. + * Man muss hier ebenfalls mitgeben ob der codierte String in Codierer.nachricht gespeichert werden soll oder nicht. + * In der Regel ist dies der Fall. + * + * @param buchstabe : char : Der zu codierende Buchstabe + * @param save : boolean : Nachricht speichern oder nicht + * @return char : Der codierte Buchstabe + */ + public char codiere(char buchstabe, boolean save) { + + char codiert = this.hardware.codiere(buchstabe); + + if (save) { + this.nachricht += codiert; + } + + return codiert; + } + + /** + * Codiert den Übergebenen String. + * Man muss hier ebenfalls mitgeben ob der codierte String in Codierer.nachricht gespeichert werden soll oder nicht. + * In der Regel ist dies der Fall. + * + * @param klartext : String : Der zu codierende Text + * @param save : boolean : Nachricht speichern oder nicht + * @return String : Der codierte Text zusätzlich als Rückgabe + */ + public String codiere(String klartext, boolean save) { + + StringBuilder sb = new StringBuilder(); + + for (char buchstabe : klartext.toCharArray()) { + sb.append(this.codiere(buchstabe, save)); + } + + return sb.toString(); + } + + /** + * Diese Funktion erwartet als (codierteNachricht) eine korrekte Enigma Nachricht. + * Ihr muss auch der Tag der codierung mitgegeben werden. Dieser weiß dein Funker im Funkraum. + * In der Regel ist dies der Tag des Nachrichten empfangs. + * + * @param codierteNachricht : String : Enigma codierte Nachricht + * @param tag : int : Tag der Nachricht + * @return String : decodierte Nachricht + */ + private String decodiere(String codierteNachricht, int tag) { + + // Hardware reseten und Tageseinstellungen aus dem Codebuch laden + this.codebuch.fetchTagesschluessel(tag); + this.initialisiereHardware(); + + // Nachricht splitten mit whitespace als delimiter + String[] nachricht = codierteNachricht.split(" "); + StringBuilder sb = new StringBuilder(); + + // Uhrzeit + sb.append(nachricht[0]).append(" "); + + // Zeichen Anzahl der Nachricht + sb.append(nachricht[1]).append(" "); + + // Spruchschlüssel + String spruchschluessel = this.decodiereString(nachricht[2]); + + sb.append(spruchschluessel).append(" "); + sb.append(this.decodiereString(nachricht[3])).append(" "); + + // Walzen neu einstellen mit dem Spruchschlüssel + this.hardware.setzePosition(0, spruchschluessel.charAt(0)); + this.hardware.setzePosition(1, spruchschluessel.charAt(1)); + this.hardware.setzePosition(2, spruchschluessel.charAt(2)); + + // Nachricht decodieren + sb.append(this.decodiereString(nachricht[4])); + + return sb.toString(); + } + + /** + * Zerlegt den übergebenen String in einen char Array und decodiert jedes Zeichen. + * Der String wird dann decodiert zurück gegeben. + * + * @param nachricht : String : Der zu decodierende Text + * @return String : Der decodierte Text + */ + private String decodiereString(String nachricht) { + + StringBuilder sb = new StringBuilder(); + + for (char buchstabe : nachricht.toCharArray()) { + if (buchstabe > 0) { + sb.append(this.hardware.codiere(buchstabe)); + } + } + + return sb.toString(); + } + //endregion + + //region Sonstige + + /** + * Prüft ob der Port auf den das Kabel gesteckt werden soll, noch frei ist. + * <p> + * setSteckbrett ausführen mit beiden Buchstaben als String + * + * @param buchstabe : char : Der zuletzt eingegebene Buchstabe + * @return boolean : Wenn der Buchstabe nicht vorhanden ist, wird true zurückgegeben, ansonsten false + */ + public boolean pruefeSteckbrettPort(char buchstabe) { + return this.hardware.getSteckbrett().ueberpruefeVertauschungen(buchstabe); + } + + /** + * Ließt aus der empfangenen Nachricht den Spruchschlüssel aus und gibt ihn zurück. + * + * @param empfangeneNachricht : String : Die empfangene Nachricht als String + * @return String : Der Spruchschlüssel mit welcher die Nachricht codiert wurde. + */ + public String empfangenerSpruchschluessel(String empfangeneNachricht) { + String[] nachricht = empfangeneNachricht.split(" "); + + return nachricht[2]; + } + + /** + * Löscht das letzte Zeichen aus der Nachricht und dreht die Walzen eine Position zurück. + */ + public void letztesZeichenLoeschen() { + this.hardware.dreheWalzen(-1); + this.nachricht = this.nachricht.substring(0, this.nachricht.length() - 1); + } + //endregion + //endregion + + //region Setter + + /** + * Setzt die Kenngruppe welche die Enigma gerade benutzt. + * + * @param kenngruppe : String : Kenngruppe welche die Enigma gerade benutzt + */ + public void setKenngruppe(String kenngruppe) { + + this.kenngruppe = kenngruppe; + this.initialisiereHardware(); + } + //endregion + + //region Getter + + /** + * Liest die Kenngruppe aus welche die Maschine gerade besitzt. Früher war dies eine eindeutige Nummer + * die einer Einheit zugewiesen war. Wir hinterlegen hier einen Benutzernamen. + * + * @return String : Kenngruppe + */ + public String getKenngruppe() { + return kenngruppe; + } + + /** + * Der Spruchschlüssel wird, zur internen Verwendung, auch im Klartext gespeichert. + * Wir brauchen diesen dann zum codieren der eigentlichen Nachricht. + * + * @return String : Der klartext Spruchschlüssel + */ + public String getSpruchschluessel() { + return this.spruchschluessel; + } + + /** + * Gibt die bisher erstellte Nachricht zurück + * + * @return String : Erstellte Nachricht + */ + public String getNachricht() { + return nachricht; + } + //endregion } diff --git a/src/main/java/projekt/enigma/model/Fehler.java b/src/main/java/projekt/enigma/model/Fehler.java index 2dfedd46bfc32b333bf0a8997f08de0419399461..2617b700baed9a77d9b3c5a249649dd20f7aaf05 100644 --- a/src/main/java/projekt/enigma/model/Fehler.java +++ b/src/main/java/projekt/enigma/model/Fehler.java @@ -9,70 +9,70 @@ import projekt.enigma.App; */ public class Fehler { - private String functionPrefix = "- "; - private String messagePrefix = "--> "; + private String functionPrefix = "- "; + private String messagePrefix = "--> "; - /** - * Zeige Fehler Dialog - * - * @param type : String : Art der Meldung (warning/information/error) - * @param subject : Titel des Dialoges - * @param message : Nachricht der Meldung - */ - public void showErrorDialog(String type, String subject, String message) { + /** + * Zeige Fehler Dialog + * + * @param type : String : Art der Meldung (warning/information/error) + * @param subject : Titel des Dialoges + * @param message : Nachricht der Meldung + */ + public void showErrorDialog(String type, String subject, String message) { - new Fehler().debug(this.getClass().getName() + "." + new Throwable().getStackTrace()[0].getMethodName(), true); + new Fehler().debug(this.getClass().getName() + "." + new Throwable().getStackTrace()[0].getMethodName(), true); - Alert alert; + Alert alert; - /* Der Titel darf auch als leerer String übergeben werden, dann wird ein Default gesetzt */ - if (subject.equals("")) { - subject = "Es ist ein Fehler aufgetreten"; - } + /* Der Titel darf auch als leerer String übergeben werden, dann wird ein Default gesetzt */ + if (subject.equals("")) { + subject = "Es ist ein Fehler aufgetreten"; + } - /* Welcher Fehler Typ wurde übergeben? */ - switch (type) { - case "warning": - alert = new Alert(AlertType.WARNING); - break; - case "information": - alert = new Alert(AlertType.INFORMATION); - break; - case "error": - alert = new Alert(AlertType.ERROR); - break; - default: - alert = new Alert(AlertType.NONE); - } - /* Setzt den Titel des Dialoges */ - alert.setTitle(subject); - /* Setzt den Headertext des Dialoges */ - alert.setHeaderText(null); - /* Setzt die Nachricht des Dialoges */ - alert.setContentText(message); - /* Zeige den Dialog an */ - alert.showAndWait(); - } + /* Welcher Fehler Typ wurde übergeben? */ + switch (type) { + case "warning": + alert = new Alert(AlertType.WARNING); + break; + case "info": + alert = new Alert(AlertType.INFORMATION); + break; + case "error": + alert = new Alert(AlertType.ERROR); + break; + default: + alert = new Alert(AlertType.NONE); + } + /* Setzt den Titel des Dialoges */ + alert.setTitle(subject); + /* Setzt den Headertext des Dialoges */ + alert.setHeaderText(null); + /* Setzt die Nachricht des Dialoges */ + alert.setContentText(message); + /* Zeige den Dialog an */ + alert.showAndWait(); + } - public void debug(String message, boolean isFunction) { + public void debug(String message, boolean isFunction) { - if (App.getDebug() != 0) { - if (isFunction) { - System.out.println(functionPrefix + message); - } else { - System.out.println(messagePrefix + message); - } - } - } + if (App.getDebug() != 0) { + if (isFunction) { + System.out.println(functionPrefix + message); + } else { + System.out.println(messagePrefix + message); + } + } + } - public void debug(String message, boolean isFunction, int debugLevel) { + public void debug(String message, boolean isFunction, int debugLevel) { - if (App.getDebug() != 0 && (App.getDebug() >= debugLevel || App.getDebug() == 3) ) { - if (isFunction) { - System.out.println(functionPrefix + message); - } else { - System.out.println(messagePrefix + message); - } - } - } + if (App.getDebug() != 0 && (App.getDebug() >= debugLevel || App.getDebug() == 3)) { + if (isFunction) { + System.out.println(functionPrefix + message); + } else { + System.out.println(messagePrefix + message); + } + } + } } \ No newline at end of file diff --git a/src/main/java/projekt/enigma/model/Funkraum.java b/src/main/java/projekt/enigma/model/Funkraum.java index d1096f0b8f6541fe951740723084326ec6466266..3310b32c5a145e4adadcb6fa73314b1d7f6731f6 100644 --- a/src/main/java/projekt/enigma/model/Funkraum.java +++ b/src/main/java/projekt/enigma/model/Funkraum.java @@ -69,7 +69,7 @@ public class Funkraum { new Fehler().showErrorDialog("error", "HTTP Post war nicht erfolgreich", "Bitte wenden Sie sich an ihren Vorgesetzten."); } catch (NullPointerException e) { - new Fehler().showErrorDialog("error", "Keiner schreibt dir...", + new Fehler().showErrorDialog("info", "Keiner schreibt dir...", "Es liegen keine neuen Nachrichten im Funkraum für Sie vor."); } diff --git a/src/main/java/projekt/enigma/model/Steckbrett.java b/src/main/java/projekt/enigma/model/Steckbrett.java index b2d698f7b576b685230f97dd524b8e7767e60147..426424bac13c717a37c9b7529a39d71436ea033e 100644 --- a/src/main/java/projekt/enigma/model/Steckbrett.java +++ b/src/main/java/projekt/enigma/model/Steckbrett.java @@ -132,4 +132,27 @@ public class Steckbrett { } } + /** + * TODO: Doku + * @param port + * @return + */ + public String fetchVerfuegbareBuchstaben(int port) { + + String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + for (char c : this.originalBuchstaben.toCharArray()) { + alphabet = alphabet.replace(String.valueOf(c), ""); + } + + for (char c : this.getauschteBuchstaben.toCharArray()) { + alphabet = alphabet.replace(String.valueOf(c), ""); + } + + alphabet += originalBuchstaben.charAt(port); + alphabet += getauschteBuchstaben.charAt(port); + + return alphabet; + } + } \ No newline at end of file diff --git a/src/main/resources/projekt/enigma/gui.fxml b/src/main/resources/projekt/enigma/gui.fxml index 541232d5cffb09e2bcd7a2c7d5a910faed867ba6..e1f89f7b45830201cfc80800a7eff6bcffcec0f3 100644 --- a/src/main/resources/projekt/enigma/gui.fxml +++ b/src/main/resources/projekt/enigma/gui.fxml @@ -8,11 +8,12 @@ <?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.GridPane?> +<?import javafx.scene.layout.Pane?> <?import javafx.scene.layout.RowConstraints?> <?import javafx.scene.shape.Circle?> <?import javafx.scene.text.Font?> -<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="677.0" prefWidth="962.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="projekt.enigma.GuiController"> +<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="677.0" prefWidth="962.0" xmlns="http://javafx.com/javafx/8.0.999-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="projekt.enigma.GuiController"> <children> <AnchorPane layoutX="207.0" layoutY="-111.0" prefHeight="111.0" prefWidth="487.0" AnchorPane.leftAnchor="207.0" AnchorPane.rightAnchor="274.0" /> <GridPane layoutX="23.0" layoutY="60.0" prefHeight="158.0" prefWidth="237.0" AnchorPane.leftAnchor="23.0" AnchorPane.topAnchor="60.0"> @@ -97,7 +98,7 @@ <Button fx:id="btnReset" mnemonicParsing="false" onAction="#gedrueckteTaste" text="Zurücksetzen" GridPane.rowIndex="1" /> </children> </GridPane> - <GridPane layoutX="6.0" layoutY="294.0" prefHeight="377.0" prefWidth="952.0" AnchorPane.bottomAnchor="6.0" AnchorPane.leftAnchor="6.0" AnchorPane.rightAnchor="9.0" AnchorPane.topAnchor="294.0"> + <GridPane fx:id="mainGrid" layoutX="6.0" layoutY="294.0" prefHeight="377.0" prefWidth="952.0" AnchorPane.bottomAnchor="6.0" AnchorPane.leftAnchor="6.0" AnchorPane.rightAnchor="9.0" AnchorPane.topAnchor="294.0"> <columnConstraints> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> @@ -669,6 +670,7 @@ <Insets left="42.0" /> </GridPane.margin> </Label> + <Pane prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="7" /> </children> </GridPane> <Label layoutX="684.0" layoutY="-164.0" prefHeight="17.0" prefWidth="195.0" />