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 + } +}