2 * Copyright (C) 2016 - 2024 Free Software Foundation
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 package org.mxchange.addressbook.client.console;
19 import java.io.IOException;
20 import java.sql.SQLException;
21 import java.text.MessageFormat;
22 import java.util.Arrays;
23 import java.util.Scanner;
24 import org.mxchange.addressbook.application.AddressbookApplication;
25 import org.mxchange.addressbook.client.AddressbookClient;
26 import org.mxchange.addressbook.client.BaseAddressbookClient;
27 import org.mxchange.addressbook.facade.contact.ContactFacade;
28 import org.mxchange.addressbook.menu.Menu;
29 import org.mxchange.addressbook.menu.MenuTools;
30 import org.mxchange.addressbook.menu.console.ConsoleMenu;
31 import org.mxchange.addressbook.menu.item.SelectableMenuItem;
32 import org.mxchange.addressbook.menu.item.console.ConsoleMenuItem;
33 import org.mxchange.jcontacts.model.contact.Contact;
34 import org.mxchange.jcontacts.model.contact.UserContact;
35 import org.mxchange.jcontacts.model.contact.title.PersonalTitle;
36 import org.mxchange.jcontacts.model.utils.PersonalTitleUtils;
37 import org.mxchange.jcontactsbusiness.exceptions.basicdata.BasicDataAlreadyAddedException;
38 import org.mxchange.jcore.application.Application;
39 import org.mxchange.jcore.exceptions.MenuInitializationException;
40 import org.mxchange.jcore.exceptions.UnhandledUserChoiceException;
43 * A client for the console
45 * @author Roland Häder<roland@mxchange.org>
47 public class ConsoleClient extends BaseAddressbookClient implements AddressbookClient {
50 * Scanner instance for reading data from console input
52 private final Scanner scanner;
55 * Parameterless constructor
57 * @param application An instance of an Application class
59 public ConsoleClient (final Application application) {
61 this.getLoggerBeanLocal().logTrace(MessageFormat.format("application={0} - CALLED!", application)); //NOI18N
63 // Set application instance
64 this.setApplication(application);
66 // Init scanner instance
67 this.scanner = new Scanner(System.in, "UTF-8"); //NOI18N
70 this.getLoggerBeanLocal().logTrace("EXIT!"); //NOI18N
74 public void displayAddressBox (final Contact contact) {
76 this.getLoggerBeanLocal().logTrace(MessageFormat.format("contact={0} - CALLED!", contact)); //NOI18N
79 if (null == contact) {
81 throw new NullPointerException("contact is null"); //NOI18N
85 this.outputMessage(MessageFormat.format("Strasse, PLZ Ort, Land: {0}\n{1} {2}\n{3}", contact.getContactStreet(), contact.getContactZipCode(), contact.getContactCity(), contact.getContactCountry()));
88 this.getLoggerBeanLocal().logTrace("EXIT!"); //NOI18N
92 public void displayNameBox (final Contact contact) {
94 this.getLoggerBeanLocal().logTrace(MessageFormat.format("contact={0} - CALLED!", contact)); //NOI18N
97 if (null == contact) {
99 throw new NullPointerException("contact is null"); //NOI18N
102 // Get translated title as the user may want to see "Mr.", "Mrs."
103 String title = PersonalTitleUtils.getTranslatedPersonalTitle(contact);
105 // Now put all together: title, surname, family name
106 this.outputMessage(MessageFormat.format("Anrede, Vorname, Name: {0} {1} {2}", title, contact.getContactFirstName(), contact.getContactFamilyName()));
109 this.getLoggerBeanLocal().logTrace("EXIT!"); //NOI18N
113 public void displayOtherDataBox (final Contact contact) {
115 this.getLoggerBeanLocal().logTrace(MessageFormat.format("contact={0} - CALLED!", contact)); //NOI18N
118 if (null == contact) {
120 throw new NullPointerException("contact is null"); //NOI18N
123 // Mobile and such ...
124 this.outputMessage(MessageFormat.format("Telefonnumer: {0}\nFaxnummer: {1}\nHandy: {2}\nKommentar:\n{3}", contact.getContactLandLineNumber(), contact.getContactFaxNumber(), contact.getContactMobileNumber(), contact.getContactComment()));
127 this.getLoggerBeanLocal().logTrace("EXIT!"); //NOI18N
131 public void doChangeOwnAddressData (final Contact contact) {
133 this.getLoggerBeanLocal().logTrace(MessageFormat.format("contact={0} - CALLED!", contact)); //NOI18N
136 if (null == contact) {
138 throw new NullPointerException("contact is null"); //NOI18N
141 // Make sure it is own contact
142 if (!contact.isOwnContact()) {
144 throw new IllegalArgumentException("Contact is not own data."); //NOI18N
147 // Get manager and cast it
148 ContactFacade manager = (ContactFacade) this.getFacade();
150 // Own street and number
151 String streetNumber = manager.enterOwnStreet();
154 Integer zipCode = manager.enterOwnZipCode();
157 String city = manager.enterOwnCity();
160 Country country = manager.enterOwnCountryCode();
162 // Update address data
163 contact.setContactStreet(streetNumber);
164 contact.setContactZipCode(zipCode);
165 contact.setContactCity(city);
166 contact.setContactCountry(country);
169 this.getLoggerBeanLocal().logTrace("EXIT!"); //NOI18N
173 public void doChangeOwnNameData (final Contact contact) {
175 this.getLoggerBeanLocal().logTrace(MessageFormat.format("contact={0} - CALLED!", contact)); //NOI18N
178 if (null == contact) {
180 throw new NullPointerException("contact is null"); //NOI18N
183 // Make sure it is own contact
184 if (!contact.isOwnContact()) {
186 throw new IllegalArgumentException("Contact is not own data."); //NOI18N
189 // Get manager and cast it
190 ContactFacade manager = (ContactFacade) this.getFacade();
193 PersonalTitle title = manager.enterOwnPersonalTitle();
196 String firstName = manager.enterOwnFirstName();
199 String familyName = manager.enterOwnFamilyName();
201 // Update contact instance
202 contact.setContactPersonalTitle(title);
203 contact.setContactFirstName(firstName);
204 contact.setContactFamilyName(familyName);
207 this.getLoggerBeanLocal().logTrace("EXIT!"); //NOI18N
211 public void doChangeOwnOtherData (final Contact contact) {
213 this.getLoggerBeanLocal().logTrace(MessageFormat.format("contact={0} - CALLED!", contact)); //NOI18N
216 if (null == contact) {
218 throw new NullPointerException("contact is null"); //NOI18N
221 // Make sure it is own contact
222 if (!contact.isOwnContact()) {
224 throw new IllegalArgumentException("Contact is not own data."); //NOI18N
227 // Get manager and cast it
228 ContactFacade manager = (ContactFacade) this.getFacade();
231 DialableLandLineNumber phoneNumber = manager.enterOwnPhoneNumber();
234 DialableMobileNumber mobileNumber = manager.enterOwnCellNumber();
237 DialableFaxNumber faxNumber = manager.enterOwnFaxNumber();
240 String email = manager.enterOwnEmailAddress();
243 String comment = manager.enterOwnComment();
245 // Update contact instance
246 contact.setContactLandLineNumber(phoneNumber);
247 contact.setContactMobileNumber(mobileNumber);
248 contact.setContactFaxNumber(faxNumber);
249 contact.setContactEmailAddress(email);
250 contact.setContactComment(comment);
253 this.getLoggerBeanLocal().logTrace("EXIT!"); //NOI18N
257 public Contact doEnterOwnData () {
259 this.getLoggerBeanLocal().logTrace("CALLED!"); //NOI18N
261 // Get manager and cast it
262 ContactFacade manager = (ContactFacade) this.getFacade();
264 // First ask for title
265 PersonalTitle title = manager.enterOwnPersonalTitle();
267 // 2nd for first name
268 String firstName = manager.enterOwnFirstName();
270 // And 3rd for family name
271 String familyName = manager.enterOwnFamilyName();
273 // Construct UserContact instance
274 Contact contact = new UserContact(title, firstName, familyName);
277 this.getLoggerBeanLocal().logTrace(MessageFormat.format("contact={0} - EXIT!", contact)); //NOI18N
284 public void doShutdown () throws SQLException, IOException {
286 this.getLoggerBeanLocal().logTrace("CALLED!"); //NOI18N
291 // TODO Add other shutdown stuff
293 this.getLoggerBeanLocal().logTrace("EXIT!"); //NOI18N
297 public void doUserMenuChoice () throws UnhandledUserChoiceException, MenuInitializationException {
299 this.getLoggerBeanLocal().logTrace("CALLED!"); //NOI18N
301 // Get all access keys from menu
302 char[] accessKeys = MenuTools.getAccessKeysFromMenuMap(this.getMenus(), this.getCurrentMenu());
304 // Output textural message and ask for a char as input
305 char choice = this.enterChar(accessKeys, "Bitte Auswahl eingeben (0=Programm beenden): ");
307 // Get manager and cast it
308 ContactFacade manager = (ContactFacade) this.getFacade();
310 // TODO Rewrite this ugly switch() block
314 // Enter/add own data
315 manager.doEnterOwnData();
316 } catch (final BasicDataAlreadyAddedException ex) {
318 this.outputMessage("Sie haben bereits Ihre eigenen Daten eingegeben.");
322 case '2': // Change own data
323 manager.doChangeOwnData();
326 case '3': // Add new addess
327 manager.doAddOtherAddress();
330 case '4': // List contacts
331 manager.doListContacts();
334 case '5': // Search addresses
335 manager.doSearchContacts();
338 case '6': // Change other addess
339 manager.doChangeOtherAddress();
342 case '7': // Delete other address
343 manager.doDeleteOtherAddress();
349 this.getApplication().doShutdown();
350 } catch (final SQLException | IOException ex) {
351 this.abortProgramWithException(ex);
356 // TODO throw own exception
357 throw new UnhandledUserChoiceException(MessageFormat.format("Choice '{0}' not handled yet.", choice)); //NOI18N
361 this.getLoggerBeanLocal().logTrace("EXIT!"); //NOI18N
365 @SuppressWarnings ("UseOfSystemOutOrSystemErr")
366 public char enterChar (final char[] validChars, final String message) {
368 this.getLoggerBeanLocal().logTrace(MessageFormat.format("validChars={0},message={1} - CALLED!", Arrays.toString(validChars), message)); //NOI18N
370 // The validChars must not null be null and filled with at least one char
371 if (null == validChars) {
373 throw new NullPointerException("validChars is null"); //NOI18N
374 } else if (validChars.length == 0) {
376 throw new IllegalArgumentException("validChars is not filled."); //NOI18N
381 // Sort array, else binarySearch() won't work
382 Arrays.sort(validChars);
384 // Keep asking until valid char has been entered
385 while (Arrays.binarySearch(validChars, input) < 0) {
387 System.out.print(message);
390 input = this.readChar();
394 this.getLoggerBeanLocal().logTrace(MessageFormat.format("input={0} - EXIT!", input)); //NOI18N
401 public PersonalTitle enterPersonalTitle (final String message) {
403 this.getLoggerBeanLocal().logTrace(MessageFormat.format("message={0} - CALLED!", message)); //NOI18N
406 char[] validChars = PersonalTitle.validChars();
409 //* NOISY-DEBUG: */ System.out.println(validChars);
411 char title = this.enterChar(validChars, message);
413 // Now get a PersonalTitle instance back
414 PersonalTitle g = PersonalTitle.fromChar(title);
416 // g must not be null
417 assert (g instanceof PersonalTitle) : "g is not set."; //NOI18N
420 this.getLoggerBeanLocal().logTrace(MessageFormat.format("g={0} - EXIT!", g)); //NOI18N
427 @SuppressWarnings ("UseOfSystemOutOrSystemErr")
428 public int enterInt (final int minimum, final int maximum, final String message) {
430 this.getLoggerBeanLocal().logTrace(MessageFormat.format("minimum={0},maximum={1},message={2} - CALLED!", minimum, maximum, message)); //NOI18N
432 // Minimum should not be below zero
433 assert (minimum >= 0) : MessageFormat.format("minimum={0} is below zero", minimum); //NOI18N
434 assert (maximum > minimum) : MessageFormat.format("maximum {0} is smaller than minimum {1}", maximum, minimum); //NOI18N
439 while ((input < minimum) || (input > maximum)) {
441 System.out.print(message);
443 // Read integer from user
444 input = this.readInt();
448 this.getLoggerBeanLocal().logTrace(MessageFormat.format("input={0} - EXIT!", input)); //NOI18N
455 @SuppressWarnings ("UseOfSystemOutOrSystemErr")
456 public String enterString (final int minLength, final int maxLength, final String message, final boolean allowEmpty) {
458 this.getLoggerBeanLocal().logTrace(MessageFormat.format("minLength={0},maxLength={1},message={2}allowEmpty={3} - CALLED!", minLength, maxLength, message, allowEmpty)); //NOI18N
460 // Check on length, e.g. country codes are excactly 2 chars long
461 assert (maxLength >= minLength);
466 // Check if it is to short or to long
467 while (((null == input) || ((input.length() < minLength) && (!allowEmpty))) || ((input.length() > 0) && (input.length() < minLength) && (allowEmpty)) || ((input instanceof String) && (input.length() > maxLength))) {
469 System.out.print(message);
472 input = this.readString();
476 this.getLoggerBeanLocal().logTrace(MessageFormat.format("input={0} - EXIT!", input)); //NOI18N
483 public SelectableMenuItem getMenuItem (final char accessKey, final String text) {
484 // Return a new console menu item
485 return new ConsoleMenuItem(accessKey, text);
489 public void init () {
491 this.getLoggerBeanLocal().logTrace("CALLED!"); //NOI18N
493 // Init contact manager here
495 this.initContactManager();
496 } catch (final SQLException ex) {
498 this.abortProgramWithException(ex);
505 this.getLoggerBeanLocal().logTrace("EXIT!"); //NOI18N
509 @SuppressWarnings ("UseOfSystemOutOrSystemErr")
510 public void outputMessage (final String message) {
511 System.out.println(message);
515 public void show (final Contact contact) {
516 throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
520 public void showCurrentMenu () {
521 this.showMenu(this.getCurrentMenu());
525 public void showEntry (final SelectableMenuItem item) {
526 // Access key then text
527 this.outputMessage(MessageFormat.format("[{0}] {1}", item.getAccessKey(), item.getText())); //NOI18N
531 public void showWelcome () {
532 this.outputMessage(MessageFormat.format("Welcome to {0}", AddressbookApplication.printableTitle())); //NOI18N
533 this.outputMessage(""); //NOI18N
534 this.outputMessage("Copyright(c) 2016 by Roland Häder, this is free software"); //NOI18N
537 this.getLoggerBeanLocal().logDebug("Intro shown to user"); //NOI18N
541 public void userChooseChangeContactData (final Contact contact) throws UnhandledUserChoiceException {
543 this.getLoggerBeanLocal().logTrace(MessageFormat.format("contact={0} CALLED!", contact)); //NOI18N
545 // Contact must not be null
546 if (null == contact) {
548 throw new NullPointerException("contact is null"); //NOI18N
551 // Ask the user for editing [name], [a]ddress or [other] data
552 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) ");
554 // Get manager and cast it
555 ContactFacade manager = (ContactFacade) this.getFacade();
557 // TODO Get rid of this ugly switch block, too
559 case 'n': // Name data
560 manager.doChangeNameData(contact);
563 case 'a': // Address data
564 manager.doChangeAddressData(contact);
567 case 'o': // Other data
568 manager.doChangeOtherData(contact);
571 case 'x': // Exit this menu
572 // Ignored as it should go back
576 // TODO throw own exception
577 throw new UnhandledUserChoiceException(MessageFormat.format("Choice '{0}' not handled yet.", choice)); //NOI18N
581 this.getLoggerBeanLocal().logTrace("EXIT!"); //NOI18N
585 * Reads one character
587 * @return A single character
589 private char readChar () {
591 String input = this.readString();
594 this.getLoggerBeanLocal().logDebug(MessageFormat.format("input={0}", input)); //NOI18N
596 // This must be only one character
597 if (input.length() != 1) {
602 // Get char from first (and only) position
603 return input.charAt(0);
607 * Reads an integer (int) from user
609 * @return An integer number
611 private int readInt () {
612 // First read a string
613 String input = this.readString();
616 this.getLoggerBeanLocal().logDebug(MessageFormat.format("input={0}", input)); //NOI18N
618 // Init number with invalid value
621 // Parse number, this can be risky
623 num = Integer.parseInt(input);
624 } catch (final NumberFormatException e) {
625 this.outputMessage("Bitte geben Sie nur Zahlen ein!");
626 this.getLoggerBeanLocal().logWarning(MessageFormat.format("No numbers-only entered. input={0},message={1}", input, e.getMessage())); //NOI18N
630 this.getLoggerBeanLocal().logTrace(MessageFormat.format("num={0} - EXIT!", num)); //NOI18N
632 // Return read number
637 * Reads a string from a scanner until RETURN is pressed
639 * @return Read string from scanner
641 private String readString () {
642 return this.scanner.nextLine();
646 protected void fillMenuMap () {
648 this.getLoggerBeanLocal().logTrace("CALLED!"); //NOI18N
650 // Initialize first (main) menu
651 Menu menu = new ConsoleMenu("main", this); //NOI18N
654 this.getMenus().put("main", menu); //NOI18N
657 this.getLoggerBeanLocal().logTrace("EXIT!"); //NOI18N