X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=Addressbook%2Fsrc%2Forg%2Fmxchange%2Faddressbook%2Fclient%2Fconsole%2FConsoleClient.java;h=176418b4f38849891d7cf7936bf4a40a467dff13;hb=fed8835173cbf96fceec08639f4a20d890fec23c;hp=82d80d824e86ceebc5353cf7cda31952d2467662;hpb=27f135983830bf9fc71b909db6c0fb97c618fccc;p=jaddressbook-lib.git
diff --git a/Addressbook/src/org/mxchange/addressbook/client/console/ConsoleClient.java b/Addressbook/src/org/mxchange/addressbook/client/console/ConsoleClient.java
index 82d80d82..176418b4 100644
--- a/Addressbook/src/org/mxchange/addressbook/client/console/ConsoleClient.java
+++ b/Addressbook/src/org/mxchange/addressbook/client/console/ConsoleClient.java
@@ -1,399 +1,739 @@
-/*
- * Copyright (C) 2015 Roland Haeder
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.mxchange.addressbook.client.console;
-
-import java.text.MessageFormat;
-import java.util.Arrays;
-import java.util.Scanner;
-import org.mxchange.addressbook.UnhandledUserChoiceException;
-import org.mxchange.addressbook.application.AddressbookApplication;
-import org.mxchange.addressbook.application.Application;
-import org.mxchange.addressbook.client.BaseClient;
-import org.mxchange.addressbook.client.Client;
-import org.mxchange.addressbook.contact.Contact;
-import org.mxchange.addressbook.menu.Menu;
-import org.mxchange.addressbook.menu.MenuTools;
-import org.mxchange.addressbook.menu.console.ConsoleMenu;
-import org.mxchange.addressbook.menu.item.SelectableMenuItem;
-import org.mxchange.addressbook.menu.item.console.ConsoleMenuItem;
-
-/**
- * A client for the console
- *
- * @author Roland Haeder
- */
-public class ConsoleClient extends BaseClient implements Client {
- /**
- * Scanner instance for reading data from console input
- */
- private final Scanner scanner;
-
- /**
- * Parameterless constructor
- * @param application An instance of an Application class
- */
- public ConsoleClient (final Application application) {
- super();
-
- // Set application instance
- this.setApplication(application);
-
- // Init scanner instance
- this.scanner = new Scanner(System.in);
- }
-
- /**
- * Displays a textual address "box" of given contact
- *
- * @param contact Contact to show address for
- * @todo Use mask
- */
- @Override
- public void displayAddressBox (final Contact contact) {
- // Simple display ...
- // @todo Use mask
- this.outputMessage("Strasse, PLZ Ort, Land: " + contact.getStreet() + "\n" + contact.getZipCode() + " " + contact.getCity() + "\n" + contact.getCountryCode());
- }
-
- /**
- * Displays a textual name "box" of given contact
- *
- * @param contact Contact to show name for
- */
- @Override
- public void displayNameBox (final Contact contact) {
- // Get translated gender as the user may want to see "Mr.", "Mrs."
- String gender = contact.getTranslatedGender();
-
- // Get company name
- String companyName = contact.getCompanyName();
-
- // If it is empty/null, then assume private contact
- if ((companyName == null) || (companyName.isEmpty())) {
- // Now put all together: gender, surname, family name
- // @todo Use mask
- this.outputMessage("Anrede, Vorname, Name: " + gender + " " + contact.getSurname() + " " + contact.getFamilyName());
- } else {
- // Company contact
- this.outputMessage("Firma: " + companyName + "\nAnsprechpartner: " + gender + " " + contact.getSurname() + " " + contact.getFamilyName());
- }
- }
-
- /**
- * Displays a textual other data "box" of given contact
- *
- * @param contact Contact to show other data for
- */
- @Override
- public void displayOtherDataBox (final Contact contact) {
- // Cellphone and such ...
- this.outputMessage("Telefonnumer: " + contact.getPhoneNumber() + "\nFaxnummer: " + contact.getFaxNumber() + "\nHandy: " + contact.getCellphoneNumber() + "\nKommentar:\n" + contact.getComment());
- }
-
- @Override
- public void doUserMenuChoice () throws UnhandledUserChoiceException {
- // Get all access keys from menu
- char[] accessKeys = MenuTools.getAccessKeysFromMenuMap(this.getMenus(), this.getCurrentMenu());
-
- // Output textural message and ask for a char as input
- char choice = this.enterChar(accessKeys, "Bitte Auswahl eingeben (0=Programm beenden): ");
-
- // @TODO Rewrite this ugly switch() block
- switch (choice) {
- case '1': // Enter/add own data
- this.getContactManager().doEnterOwnData();
- break;
-
- case '2': // Change own data
- this.getContactManager().changeOwnData();
- break;
-
- case '3': // Add new addess
- this.getContactManager().addOtherAddress();
- break;
-
- case '4': // List contacts
- this.getContactManager().listContacts();
- break;
-
- case '5': // Search addresses
- this.getContactManager().searchContacts();
- break;
-
- case '6': // Change other addess
- this.getContactManager().changeOtherAddress();
- break;
-
- case '7': // Delete other address
- this.getContactManager().deleteOtherAddress();
- break;
-
- case '0': // Program exit
- this.disableIsRunning();
- break;
-
- default:
- // @TODO throw own exception
- throw new UnhandledUserChoiceException("Choice '" + choice + "' not handled yet.");
- }
- }
-
- /**
- * Asks the the user to enter a single character which must match validChars
- * @param validChars Valid chars that are accepted
- * @param message Message to user
- * @return Allowed character
- */
- @Override
- public char enterChar (final char[] validChars, final String message) {
- char input = 0;
-
- // Sort array, else binarySearch() won't work
- Arrays.sort(validChars);
-
- // Keep asking until valid char has been entered
- while (Arrays.binarySearch(validChars, input) < 0) {
- // Output message
- System.out.print(message);
-
- // Read char
- input = this.readChar();
- }
-
- // Return read char
- return input;
- }
-
- /**
- * Reads an integer (int) with a textural message from the user
- *
- * @param minimum Minimum allowed number
- * @param maximum Maximum allowed number
- * @param message Messager to display in console
- * @return
- */
- @Override
- public int enterInt (final int minimum, final int maximum, final String message) {
- // Minimum should not be below zero
- assert(minimum >= 0);
- assert(maximum > minimum);
-
- // Init input
- int input = -1;
-
- while ((input < minimum) || (input > maximum)) {
- // Output message
- System.out.print(message);
-
- // Read integer from user
- input = this.readInt();
- }
-
- // Return it
- return input;
- }
-
- /**
- * Reads a string of minimum and maximum length from the user
- *
- * @param minLength Minimum length of the string to read
- * @param maxLength Maximum length of the string to read
- * @param message Message to user
- * @param allowEmpty Whether to allow empty string
- * @return Entered string by user or null for empty strings
- */
- @Override
- public String enterString (final int minLength, final int maxLength, final String message, final boolean allowEmpty) {
- // Check on length, e.g. country codes are excactly 2 chars long
- assert(maxLength >= minLength);
-
- // Init input
- String input = null;
-
- // Check if it is to short or to long
- while (((input == null) || ((input.length() < minLength) && (!allowEmpty))) || ((input.length() > 0) && (input.length() < minLength) && (allowEmpty)) || ((input instanceof String) && (input.length() > maxLength))) {
- // Output message
- System.out.print(message);
-
- // Read line
- input = this.readString();
- }
-
- // Return it
- return input;
- }
-
- /**
- * Returns a console menu item
- *
- * @param accessKey Key to access the menu
- * @param text Text to show to user
- * @return A SelectableMenuItem
- * @todo Make sure the access key is unique
- */
- @Override
- public SelectableMenuItem getMenuItem (final char accessKey, final String text) {
- // Return a new console menu item
- return new ConsoleMenuItem(accessKey,text);
- }
-
- /**
- * Inizializes this client
- */
- @Override
- public void initClient () {
- // Init contact manager here
- this.initContactManager();
-
- // Fill menu map
- this.fillMenuMap();
- }
-
- /**
- * Displays textural message to the user
- * @param message
- */
- @Override
- public void outputMessage (final String message) {
- System.out.println(message);
- }
-
- /**
- * Shows textural menu on console
- */
- @Override
- public void showCurrentMenu () {
- this.showMenu(this.getCurrentMenu());
- }
-
- /**
- * Shows given menu entry to user
- *
- * @param item Menu entry
- */
- @Override
- public void showEntry (final SelectableMenuItem item) {
- // Access key then text
- this.outputMessage("[" + item.getAccessKey() + "] " + item.getText());
- }
-
- /**
- * Shows a textural message to the user
- */
- @Override
- public void showWelcome () {
- this.outputMessage("Welcome to " + AddressbookApplication.APP_TITLE + " v" + AddressbookApplication.APP_VERSION);
- this.outputMessage("");
- this.outputMessage("Copyright(c) 2015 by Roland Haeder, this is free software");
-
- // Debug message
- this.getLogger().debug("Intro shown to user");
- }
-
- @Override
- public void userChooseChangeContactData (final Contact contact) throws UnhandledUserChoiceException {
- // Ask the user for editing [name], [a]ddress or [other] data
- char choice = this.enterChar(new char[]{'n', 'a', 'o', 'x'}, "Welchen Daten möchten Sie ändern? (n=Namensdaten, a=Anschriftsdaten, o=Andere, x=Zurück zur Hauptauswahl) ");
-
- // @TODO Get rid of this ugly switch block, too
- switch (choice) {
- case 'n': // Name data
- this.getContactManager().doChangeNameData(contact, this);
- break;
-
- case 'a': // Address data
- this.getContactManager().doChangeAddressData(contact, this);
- break;
-
- case 'o': // Other data
- this.getContactManager().doChangeOtherData(contact, this);
- break;
-
- case 'x': // Exit this menu
- // Ignored as it should go back
- break;
-
- default:
- // @TODO throw own exception
- throw new UnhandledUserChoiceException("Choice '" + choice + "' not handled yet.");
- }
- }
-
- /**
- * Reads one character
- *
- * @return A single character
- */
- private char readChar () {
- // Read line
- String input = this.scanner.nextLine();
-
- // This must be only one character
- if (input.length() != 1) {
- // Return zero
- return 0;
- }
-
- // Get char from first (and only) position
- return input.charAt(0);
- }
-
- /**
- * Reads an integer (int) from user
- *
- * @return An integer number
- */
- private int readInt () {
- // First read a string
- String input = this.readString();
-
- // Init number with invalid value
- int num = -1;
-
- // Parse number, this can be risky
- try {
- num = Integer.parseInt(input);
- } catch (final NumberFormatException e) {
- this.outputMessage("Bitte geben Sie nur Zahlen ein!");
- this.getLogger().warn(MessageFormat.format("No numbers-only entered. input={0},message={1}", input, e.getMessage()));
- }
-
- // Return read number
- return num;
- }
-
- /**
- * Reads a string from a scanner until RETURN is pressed
- *
- * @return Read string from scanner
- */
- private String readString () {
- return this.scanner.nextLine();
- }
-
- /**
- * Fills menu map with menu entries
- */
- @Override
- protected final void fillMenuMap () {
- // Initialize first (main) menu
- Menu menu = new ConsoleMenu("main", this);
-
- // Add it
- this.getMenus().put("main", menu);
- }
-}
+/*
+ * Copyright (C) 2015 Roland Haeder
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.mxchange.addressbook.client.console;
+
+import java.sql.SQLException;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.Scanner;
+import org.mxchange.addressbook.application.AddressbookApplication;
+import org.mxchange.addressbook.client.AddressbookClient;
+import org.mxchange.addressbook.client.BaseAddressbookClient;
+import org.mxchange.addressbook.contact.user.UserContact;
+import org.mxchange.addressbook.exceptions.ContactAlreadyAddedException;
+import org.mxchange.addressbook.manager.contact.ManageableAddressbookContact;
+import org.mxchange.addressbook.menu.Menu;
+import org.mxchange.addressbook.menu.MenuTools;
+import org.mxchange.addressbook.menu.console.ConsoleMenu;
+import org.mxchange.addressbook.menu.item.SelectableMenuItem;
+import org.mxchange.addressbook.menu.item.console.ConsoleMenuItem;
+import org.mxchange.jcore.application.Application;
+import org.mxchange.jcore.contact.Contact;
+import org.mxchange.jcore.contact.Gender;
+import org.mxchange.jcore.exceptions.UnhandledUserChoiceException;
+import org.mxchange.jcore.exceptions.UnsupportedDatabaseBackendException;
+
+/**
+ * A client for the console
+ *
+ * @author Roland Haeder
+ */
+public class ConsoleClient extends BaseAddressbookClient implements AddressbookClient {
+
+ /**
+ * Scanner instance for reading data from console input
+ */
+ private final Scanner scanner;
+
+ /**
+ * Parameterless constructor
+ *
+ * @param application An instance of an Application class
+ */
+ public ConsoleClient (final Application application) {
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("application={0} - CALLED!", application)); //NOI18N
+
+ // Set application instance
+ this.setApplication(application);
+
+ // Init scanner instance
+ this.scanner = new Scanner(System.in, "UTF-8"); //NOI18N
+
+ // Trace message
+ this.getLogger().trace("EXIT!"); //NOI18N
+ }
+
+ /**
+ * Displays a textual address "box" of given contact
+ *
+ * @param contact Contact to show address for
+ */
+ @Override
+ public void displayAddressBox (final Contact contact) {
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("contact={0} - CALLED!", contact)); //NOI18N
+
+ // Is it null?
+ if (contact == null) {
+ // Abort here
+ throw new NullPointerException("contact is null"); //NOI18N
+ }
+
+ // Simple display ...
+ this.outputMessage(MessageFormat.format("Strasse, PLZ Ort, Land: {0}\n{1} {2}\n{3}", contact.getStreet(), contact.getZipCode(), contact.getCity(), contact.getCountryCode()));
+
+ // Trace message
+ this.getLogger().trace("EXIT!"); //NOI18N
+ }
+
+ /**
+ * Displays a textual name "box" of given contact
+ *
+ * @param contact Contact to show name for
+ */
+ @Override
+ public void displayNameBox (final Contact contact) {
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("contact={0} - CALLED!", contact)); //NOI18N
+
+ // Is it null?
+ if (contact == null) {
+ // Abort here
+ throw new NullPointerException("contact is null"); //NOI18N
+ }
+
+ // Get translated gender as the user may want to see "Mr.", "Mrs."
+ String gender = contact.getTranslatedGender();
+
+ // Get company name
+ String companyName = contact.getCompanyName();
+
+ // If it is empty/null, then assume private contact
+ if ((companyName == null) || (companyName.isEmpty())) {
+ // Now put all together: gender, surname, family name
+ // @todo Use mask
+ this.outputMessage(MessageFormat.format("Anrede, Vorname, Name: {0} {1} {2}", gender, contact.getSurname(), contact.getFamilyName()));
+ } else {
+ // Company contact
+ this.outputMessage(MessageFormat.format("Firma: {0}\nAnsprechpartner: {1} {2} {3}", companyName, gender, contact.getSurname(), contact.getFamilyName()));
+ }
+
+ // Trace message
+ this.getLogger().trace("EXIT!"); //NOI18N
+ }
+
+ /**
+ * Displays a textual other data "box" of given contact
+ *
+ * @param contact Contact to show other data for
+ */
+ @Override
+ public void displayOtherDataBox (final Contact contact) {
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("contact={0} - CALLED!", contact)); //NOI18N
+
+ // Is it null?
+ if (contact == null) {
+ // Abort here
+ throw new NullPointerException("contact is null"); //NOI18N
+ }
+
+ // Cellphone and such ...
+ this.outputMessage(MessageFormat.format("Telefonnumer: {0}\nFaxnummer: {1}\nHandy: {2}\nKommentar:\n{3}", contact.getPhoneNumber(), contact.getFaxNumber(), contact.getCellphoneNumber(), contact.getComment()));
+
+ // Trace message
+ this.getLogger().trace("EXIT!"); //NOI18N
+ }
+
+ @Override
+ public void doChangeOwnAddressData (final Contact contact) {
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("contact={0} - CALLED!", contact)); //NOI18N
+
+ // Is it null?
+ if (contact == null) {
+ // Abort here
+ throw new NullPointerException("contact is null"); //NOI18N
+ }
+
+ // Make sure it is own contact
+ if (!contact.isOwnContact()) {
+ // Not own contact
+ throw new IllegalArgumentException("Contact is not own data."); //NOI18N
+ }
+
+ // Get manager and cast it
+ ManageableAddressbookContact manager = (ManageableAddressbookContact) this.getManager();
+
+ // Own street and number
+ String streetNumber = manager.enterOwnStreet();
+
+ // Get zip code
+ Long zipCode = (long) manager.enterOwnZipCode();
+
+ // Get city name
+ String city = manager.enterOwnCity();
+
+ // Get country code
+ String countryCode = manager.enterOwnCountryCode();
+
+ // Update address data
+ contact.setStreet(streetNumber);
+ contact.setZipCode(zipCode);
+ contact.setCity(city);
+ contact.setCountryCode(countryCode);
+
+ // Trace message
+ this.getLogger().trace("EXIT!"); //NOI18N
+ }
+
+ @Override
+ public void doChangeOwnNameData (final Contact contact) {
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("contact={0} - CALLED!", contact)); //NOI18N
+
+ // Is it null?
+ if (contact == null) {
+ // Abort here
+ throw new NullPointerException("contact is null"); //NOI18N
+ }
+
+ // Make sure it is own contact
+ if (!contact.isOwnContact()) {
+ // Not own contact
+ throw new IllegalArgumentException("Contact is not own data."); //NOI18N
+ }
+
+ // Get manager and cast it
+ ManageableAddressbookContact manager = (ManageableAddressbookContact) this.getManager();
+
+ // Gender:
+ Gender gender = manager.enterOwnGender();
+
+ // Surname
+ String surname = manager.enterOwnSurname();
+
+ // Family name
+ String familyName = manager.enterOwnFamilyName();
+
+ // And company
+ String companyName = manager.enterOwnCompanyName();
+
+ // Update contact instance
+ contact.setGender(gender);
+ contact.setSurname(surname);
+ contact.setFamilyName(familyName);
+ contact.setCompanyName(companyName);
+
+ // Trace message
+ this.getLogger().trace("EXIT!"); //NOI18N
+ }
+
+ @Override
+ public void doChangeOwnOtherData (final Contact contact) {
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("contact={0} - CALLED!", contact)); //NOI18N
+
+ // Is it null?
+ if (contact == null) {
+ // Abort here
+ throw new NullPointerException("contact is null"); //NOI18N
+ }
+
+ // Make sure it is own contact
+ if (!contact.isOwnContact()) {
+ // Not own contact
+ throw new IllegalArgumentException("Contact is not own data."); //NOI18N
+ }
+
+ // Get manager and cast it
+ ManageableAddressbookContact manager = (ManageableAddressbookContact) this.getManager();
+
+ // Phone number
+ String phoneNumber = manager.enterOwnPhoneNumber();
+
+ // Phone number
+ String cellphonePhoneNumber = manager.enterOwnCellNumber();
+
+ // Fax number
+ String faxNumber = manager.enterOwnFaxNumber();
+
+ // Email address
+ String email = manager.enterOwnEmailAddress();
+
+ // Comment
+ String comment = manager.enterOwnComment();
+
+ // Update contact instance
+ contact.setPhoneNumber(phoneNumber);
+ contact.setCellphoneNumber(cellphonePhoneNumber);
+ contact.setFaxNumber(faxNumber);
+ contact.setEmailAddress(email);
+ contact.setComment(comment);
+
+ // Trace message
+ this.getLogger().trace("EXIT!"); //NOI18N
+ }
+
+ @Override
+ public Contact doEnterOwnData () {
+ // Trace message
+ this.getLogger().trace("CALLED!"); //NOI18N
+
+ // Get manager and cast it
+ ManageableAddressbookContact manager = (ManageableAddressbookContact) this.getManager();
+
+ // First ask for gender
+ Gender gender = manager.enterOwnGender();
+
+ // 2nd for surname
+ String surname = manager.enterOwnSurname();
+
+ // And 3rd for family name
+ String familyName = manager.enterOwnFamilyName();
+
+ // Company name ...
+ String companyName = manager.enterOwnCompanyName();
+
+ // Construct UserContact instance
+ Contact contact = new UserContact(gender, surname, familyName, companyName);
+
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("contact={0} - EXIT!", contact)); //NOI18N
+
+ // And return object
+ return contact;
+ }
+
+ /**
+ * Shutdown this client
+ */
+ @Override
+ public void doShutdown () {
+ // Trace message
+ this.getLogger().trace("CALLED!"); //NOI18N
+
+ // Parent call
+ super.doShutdown();
+
+ // @TODO Add other shutdown stuff
+
+ // Trace message
+ this.getLogger().trace("EXIT!"); //NOI18N
+ }
+
+ @Override
+ public void doUserMenuChoice () throws UnhandledUserChoiceException {
+ // Trace message
+ this.getLogger().trace("CALLED!"); //NOI18N
+
+ // Get all access keys from menu
+ char[] accessKeys = MenuTools.getAccessKeysFromMenuMap(this.getMenus(), this.getCurrentMenu());
+
+ // Output textural message and ask for a char as input
+ char choice = this.enterChar(accessKeys, "Bitte Auswahl eingeben (0=Programm beenden): ");
+
+ // Get manager and cast it
+ ManageableAddressbookContact manager = (ManageableAddressbookContact) this.getManager();
+
+ // @TODO Rewrite this ugly switch() block
+ switch (choice) {
+ case '1':
+ try {
+ // Enter/add own data
+ manager.doEnterOwnData();
+ } catch (final ContactAlreadyAddedException ex) {
+ // Already added
+ this.outputMessage("Sie haben bereits Ihre eigenen Daten eingegeben.");
+ }
+ break;
+
+ case '2': // Change own data
+ manager.doChangeOwnData();
+ break;
+
+ case '3': // Add new addess
+ manager.doAddOtherAddress();
+ break;
+
+ case '4': // List contacts
+ manager.doListContacts();
+ break;
+
+ case '5': // Search addresses
+ manager.doSearchContacts();
+ break;
+
+ case '6': // Change other addess
+ manager.doChangeOtherAddress();
+ break;
+
+ case '7': // Delete other address
+ manager.doDeleteOtherAddress();
+ break;
+
+ case '0': // Program exit
+ this.getApplication().doShutdown();
+ break;
+
+ default:
+ // @TODO throw own exception
+ throw new UnhandledUserChoiceException(MessageFormat.format("Choice '{0}' not handled yet.", choice)); //NOI18N
+ }
+
+ // Trace message
+ this.getLogger().trace("EXIT!"); //NOI18N
+ }
+
+ /**
+ * Asks the the user to enter a single character which must match validChars
+ *
+ * @param validChars Valid chars that are accepted
+ * @param message Message to user
+ * @return Allowed character
+ */
+ @Override
+ public char enterChar (final char[] validChars, final String message) {
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("validChars={0},message={1} - CALLED!", Arrays.toString(validChars), message)); //NOI18N
+
+ // The validChars must not null be null and filled with at least one char
+ if (validChars == null) {
+ // Is null
+ throw new NullPointerException("validChars is null"); //NOI18N
+ } else if (validChars.length == 0) {
+ // Is not filled
+ throw new IllegalArgumentException("validChars is not filled."); //NOI18N
+ }
+
+ char input = 0;
+
+ // Sort array, else binarySearch() won't work
+ Arrays.sort(validChars);
+
+ // Keep asking until valid char has been entered
+ while (Arrays.binarySearch(validChars, input) < 0) {
+ // Output message
+ System.out.print(message);
+
+ // Read char
+ input = this.readChar();
+ }
+
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("input={0} - EXIT!", input)); //NOI18N
+
+ // Return read char
+ return input;
+ }
+
+ /**
+ * Asks the user to enter his/her gender
+ *
+ * @param message Message to the user
+ * @return Gender enum
+ */
+ @Override
+ public Gender enterGender (final String message) {
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("message={0} - CALLED!", message)); //NOI18N
+
+ // Get valid chars
+ char[] validChars = Gender.validChars();
+
+ // Debug message
+ //* NOISY-DEBUG: */ System.out.println(validChars);
+ // Call inner method
+ char gender = this.enterChar(validChars, message);
+
+ // Now get a Gender instance back
+ Gender g = Gender.fromChar(gender);
+
+ // g must not be null
+ assert(g instanceof Gender) : "g is not set."; //NOI18N
+
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("g={0} - EXIT!", g)); //NOI18N
+
+ // Return it
+ return g;
+ }
+
+ /**
+ * Reads an integer (int) with a textural message from the user
+ *
+ * @param minimum Minimum allowed number
+ * @param maximum Maximum allowed number
+ * @param message Messager to display in console
+ * @return
+ */
+ @Override
+ public int enterInt (final int minimum, final int maximum, final String message) {
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("minimum={0},maximum={1},message={2} - CALLED!", minimum, maximum, message)); //NOI18N
+
+ // Minimum should not be below zero
+ assert (minimum >= 0);
+ assert (maximum > minimum);
+
+ // Init input
+ int input = -1;
+
+ while ((input < minimum) || (input > maximum)) {
+ // Output message
+ System.out.print(message);
+
+ // Read integer from user
+ input = this.readInt();
+ }
+
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("input={0} - EXIT!", input)); //NOI18N
+
+ // Return it
+ return input;
+ }
+
+ /**
+ * Reads a string of minimum and maximum length from the user
+ *
+ * @param minLength Minimum length of the string to read
+ * @param maxLength Maximum length of the string to read
+ * @param message Message to user
+ * @param allowEmpty Whether to allow empty string
+ * @return Entered string by user or null for empty strings
+ */
+ @Override
+ public String enterString (final int minLength, final int maxLength, final String message, final boolean allowEmpty) {
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("minLength={0},maxLength={1},message={2}allowEmpty={3} - CALLED!", minLength, maxLength, message, allowEmpty)); //NOI18N
+
+ // Check on length, e.g. country codes are excactly 2 chars long
+ assert (maxLength >= minLength);
+
+ // Init input
+ String input = null;
+
+ // Check if it is to short or to long
+ while (((input == null) || ((input.length() < minLength) && (!allowEmpty))) || ((input.length() > 0) && (input.length() < minLength) && (allowEmpty)) || ((input instanceof String) && (input.length() > maxLength))) {
+ // Output message
+ System.out.print(message);
+
+ // Read line
+ input = this.readString();
+ }
+
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("input={0} - EXIT!", input)); //NOI18N
+
+ // Return it
+ return input;
+ }
+
+ /**
+ * Returns a console menu item
+ *
+ * @param accessKey Key to access the menu
+ * @param text Text to show to user
+ * @return A SelectableMenuItem
+ * @todo Make sure the access key is unique
+ */
+ @Override
+ public SelectableMenuItem getMenuItem (final char accessKey, final String text) {
+ // Return a new console menu item
+ return new ConsoleMenuItem(accessKey, text);
+ }
+
+ /**
+ * Initializes this client
+ */
+ @Override
+ public void init () {
+ // Trace message
+ this.getLogger().trace("CALLED!"); //NOI18N
+
+ // Init contact manager here
+ try {
+ this.initContactManager();
+ } catch (final UnsupportedDatabaseBackendException | SQLException ex) {
+ // End here
+ this.abortProgramWithException(ex);
+ }
+
+ // Fill menu map
+ this.fillMenuMap();
+
+ // Trace message
+ this.getLogger().trace("EXIT!"); //NOI18N
+ }
+
+ /**
+ * Displays textural message to the user
+ *
+ * @param message
+ */
+ @Override
+ public void outputMessage (final String message) {
+ System.out.println(message);
+ }
+
+ /**
+ * Shows textural menu on console
+ */
+ @Override
+ public void showCurrentMenu () {
+ this.showMenu(this.getCurrentMenu());
+ }
+
+ /**
+ * Shows given menu entry to user
+ *
+ * @param item Menu entry
+ */
+ @Override
+ public void showEntry (final SelectableMenuItem item) {
+ // Access key then text
+ this.outputMessage(MessageFormat.format("[{0}] {1}", item.getAccessKey(), item.getText()));
+ }
+
+ /**
+ * Shows a textural message to the user
+ */
+ @Override
+ public void showWelcome () {
+ this.outputMessage(MessageFormat.format("Welcome to {0}", AddressbookApplication.printableTitle()));
+ this.outputMessage("");
+ this.outputMessage("Copyright(c) 2015 by Roland Haeder, this is free software");
+
+ // Debug message
+ this.getLogger().debug("Intro shown to user"); //NOI18N
+ }
+
+ @Override
+ public void userChooseChangeContactData (final Contact contact) throws UnhandledUserChoiceException {
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("contact={0} CALLED!", contact)); //NOI18N
+
+ // Contact must not be null
+ if (contact == null) {
+ // Abort here
+ throw new NullPointerException("contact is null"); //NOI18N
+ }
+
+ // Ask the user for editing [name], [a]ddress or [other] data
+ char choice = this.enterChar(new char[] {'n', 'a', 'o', 'x'}, "Welchen Daten möchten Sie ändern? (n=Namensdaten, a=Anschriftsdaten, o=Andere, x=Zurück zur Hauptauswahl) ");
+
+ // Get manager and cast it
+ ManageableAddressbookContact manager = (ManageableAddressbookContact) this.getManager();
+
+ // @TODO Get rid of this ugly switch block, too
+ switch (choice) {
+ case 'n': // Name data
+ manager.doChangeNameData(contact);
+ break;
+
+ case 'a': // Address data
+ manager.doChangeAddressData(contact);
+ break;
+
+ case 'o': // Other data
+ manager.doChangeOtherData(contact);
+ break;
+
+ case 'x': // Exit this menu
+ // Ignored as it should go back
+ break;
+
+ default:
+ // @TODO throw own exception
+ throw new UnhandledUserChoiceException(MessageFormat.format("Choice '{0}' not handled yet.", choice)); //NOI18N
+ }
+
+ // Trace message
+ this.getLogger().trace("EXIT!"); //NOI18N
+ }
+
+ /**
+ * Reads one character
+ *
+ * @return A single character
+ */
+ private char readChar () {
+ // Read line
+ String input = this.readString();
+
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("input={0}", input)); //NOI18N
+
+ // This must be only one character
+ if (input.length() != 1) {
+ // Return zero
+ return 0;
+ }
+
+ // Get char from first (and only) position
+ return input.charAt(0);
+ }
+
+ /**
+ * Reads an integer (int) from user
+ *
+ * @return An integer number
+ */
+ private int readInt () {
+ // First read a string
+ String input = this.readString();
+
+ // Debug message
+ this.getLogger().debug(MessageFormat.format("input={0}", input)); //NOI18N
+
+ // Init number with invalid value
+ int num = -1;
+
+ // Parse number, this can be risky
+ try {
+ num = Integer.parseInt(input);
+ } catch (final NumberFormatException e) {
+ this.outputMessage("Bitte geben Sie nur Zahlen ein!");
+ this.getLogger().warn(MessageFormat.format("No numbers-only entered. input={0},message={1}", input, e.getMessage())); //NOI18N
+ }
+
+ // Trace message
+ this.getLogger().trace(MessageFormat.format("num={0} - EXIT!", num)); //NOI18N
+
+ // Return read number
+ return num;
+ }
+
+ /**
+ * Reads a string from a scanner until RETURN is pressed
+ *
+ * @return Read string from scanner
+ */
+ private String readString () {
+ return this.scanner.nextLine();
+ }
+
+ /**
+ * Fills menu map with menu entries
+ */
+ @Override
+ protected final void fillMenuMap () {
+ // Trace message
+ this.getLogger().trace("CALLED!"); //NOI18N
+
+ // Initialize first (main) menu
+ Menu menu = new ConsoleMenu("main", this); //NOI18N
+
+ // Add it
+ this.getMenus().put("main", menu); //NOI18N
+
+ // Trace message
+ this.getLogger().trace("EXIT!"); //NOI18N
+ }
+}