]> git.mxchange.org Git - jaddressbook-share-lib.git/blob - Addressbook/src/org/mxchange/addressbook/client/console/ConsoleClient.java
Added trace messages
[jaddressbook-share-lib.git] / Addressbook / src / org / mxchange / addressbook / client / console / ConsoleClient.java
1 /*
2  * Copyright (C) 2015 Roland Haeder
3  *
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.
8  *
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.
13  *
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/>.
16  */
17 package org.mxchange.addressbook.client.console;
18
19 import java.text.MessageFormat;
20 import java.util.Arrays;
21 import java.util.Scanner;
22 import org.mxchange.addressbook.application.AddressbookApplication;
23 import org.mxchange.addressbook.application.Application;
24 import org.mxchange.addressbook.client.BaseClient;
25 import org.mxchange.addressbook.client.Client;
26 import org.mxchange.addressbook.contact.Contact;
27 import org.mxchange.addressbook.contact.user.UserContact;
28 import org.mxchange.addressbook.exceptions.UnhandledUserChoiceException;
29 import org.mxchange.addressbook.menu.Menu;
30 import org.mxchange.addressbook.menu.MenuTools;
31 import org.mxchange.addressbook.menu.console.ConsoleMenu;
32 import org.mxchange.addressbook.menu.item.SelectableMenuItem;
33 import org.mxchange.addressbook.menu.item.console.ConsoleMenuItem;
34
35 /**
36  * A client for the console
37  *
38  * @author Roland Haeder
39  */
40 public class ConsoleClient extends BaseClient implements Client {
41     /**
42      * Scanner instance for reading data from console input
43      */
44     private final Scanner scanner;
45
46     /**
47      * Parameterless constructor
48      * @param application An instance of an Application class
49      */
50     public ConsoleClient (final Application application) {
51         super();
52
53         // Set application instance
54         this.setApplication(application);
55
56         // Init scanner instance
57         this.scanner = new Scanner(System.in);
58     }
59
60     /**
61      * Displays a textual address "box" of given contact
62      *
63      * @param contact Contact to show address for
64      */
65     @Override
66     public void displayAddressBox (final Contact contact) {
67         // Simple display ...
68         this.outputMessage(MessageFormat.format("Strasse, PLZ Ort, Land: {0}\n{1} {2}\n{3}", contact.getStreet(), contact.getZipCode(), contact.getCity(), contact.getCountryCode()));
69     }
70
71     /**
72      * Displays a textual name "box" of given contact
73      *
74      * @param contact Contact to show name for
75      */
76     @Override
77     public void displayNameBox (final Contact contact) {
78         // Get translated gender as the user may want to see "Mr.", "Mrs."
79         String gender = contact.getTranslatedGender();
80
81         // Get company name
82         String companyName = contact.getCompanyName();
83
84         // If it is empty/null, then assume private contact
85         if ((companyName == null) || (companyName.isEmpty())) {
86             // Now put all together: gender, surname, family name
87             // @todo Use mask
88             this.outputMessage(MessageFormat.format("Anrede, Vorname, Name: {0} {1} {2}", gender, contact.getSurname(), contact.getFamilyName()));
89         } else {
90             // Company contact
91             this.outputMessage(MessageFormat.format("Firma: {0}\nAnsprechpartner: {1} {2} {3}", companyName, gender, contact.getSurname(), contact.getFamilyName()));
92         }
93     }
94
95     /**
96      * Displays a textual other data "box" of given contact
97      *
98      * @param contact Contact to show other data for
99      */
100     @Override
101     public void displayOtherDataBox (final Contact contact) {
102         // Cellphone and such ...
103         this.outputMessage(MessageFormat.format("Telefonnumer: {0}\nFaxnummer: {1}\nHandy: {2}\nKommentar:\n{3}", contact.getPhoneNumber(), contact.getFaxNumber(), contact.getCellphoneNumber(), contact.getComment()));
104     }
105
106     @Override
107     public void doChangeOwnAddressData (final Contact contact) {
108         // Make sure it is own contact
109         if (!contact.isOwnContact()) {
110             // Not own contact
111             throw new IllegalArgumentException("Contact is not own data.");
112         }
113
114         // Own address data
115         String street = this.getContactManager().enterOwnStreet();
116
117         // Get zip code
118         int zipCode = this.getContactManager().enterOwnZipCode();
119
120         // Get city name
121         String city = this.getContactManager().enterOwnCity();
122
123         // Get country code
124         String countryCode = this.getContactManager().enterOwnCountryCode();
125
126         // Update address data
127         contact.updateAddressData(street, zipCode, city, countryCode);
128     }
129
130     @Override
131     public void doChangeOwnNameData (final Contact contact) {
132         // Make sure it is own contact
133         if (!contact.isOwnContact()) {
134             // Not own contact
135             throw new IllegalArgumentException("Contact is not own data.");
136         }
137
138         // Gender:
139         char gender = this.getContactManager().enterOwnGender();
140
141         // Surname
142         String surname = this.getContactManager().enterOwnSurname();
143
144         // Family name
145         String familyName = this.getContactManager().enterOwnFamilyName();
146
147         // And company
148         String companyName = this.getContactManager().enterOwnCompanyName();
149
150         // Update contact instance
151         contact.updateNameData(gender, surname, familyName, companyName);
152     }
153
154     @Override
155     public void doChangeOwnOtherData (final Contact contact) {
156         // Make sure it is own contact
157         if (!contact.isOwnContact()) {
158             // Not own contact
159             throw new IllegalArgumentException("Contact is not own data.");
160         }
161
162         // Phone number
163         String phoneNumber = this.getContactManager().enterOwnPhoneNumber();
164
165         // Phone number
166         String cellNumber = this.getContactManager().enterOwnCellNumber();
167
168         // Fax number
169         String faxNumber = this.getContactManager().enterOwnFaxNumber();
170
171         // Email address
172         String email = this.getContactManager().enterOwnEmailAddress();
173
174         // Comment
175         String comment = this.getContactManager().enterOwnComment();
176
177         // Update contact instance
178         contact.updateOtherData(phoneNumber, cellNumber, faxNumber, email, null, comment);
179     }
180
181     @Override
182     public Contact doEnterOwnData () {
183         // First ask for gender
184         char gender = this.getContactManager().enterOwnGender();
185
186         // 2nd for surname
187         String surname = this.getContactManager().enterOwnSurname();
188         
189         // And 3rd for family name
190         String familyName = this.getContactManager().enterOwnFamilyName();
191
192         // Company name ...
193         String companyName = this.getContactManager().enterOwnCompanyName();
194
195         // Construct UserContact instance
196         Contact contact = new UserContact(gender, surname, familyName, companyName);
197
198         // And return object
199         return contact;
200     }
201
202     /**
203      * Shutdown this client
204      */
205     @Override
206     public void doShutdown () {
207         // Parent call
208         super.doShutdown();
209
210         // @TODO Add other shutdown stuff
211     }
212
213     @Override
214     public void doUserMenuChoice () throws UnhandledUserChoiceException {
215         // Get all access keys from menu
216         char[] accessKeys = MenuTools.getAccessKeysFromMenuMap(this.getMenus(), this.getCurrentMenu());
217
218         // Output textural message and ask for a char as input
219         char choice = this.enterChar(accessKeys, "Bitte Auswahl eingeben (0=Programm beenden): ");
220
221         // @TODO Rewrite this ugly switch() block
222         switch (choice) {
223             case '1': // Enter/add own data
224                 this.getContactManager().doEnterOwnData();
225                 break;
226         
227             case '2': // Change own data
228                 this.getContactManager().doChangeOwnData();
229                 break;
230         
231             case '3': // Add new addess
232                 this.getContactManager().doAddOtherAddress();
233                 break;
234         
235             case '4': // List contacts
236                 this.getContactManager().doListContacts();
237                 break;
238         
239             case '5': // Search addresses
240                 this.getContactManager().doSearchContacts();
241                 break;
242
243             case '6': // Change other addess
244                 this.getContactManager().doChangeOtherAddress();
245                 break;
246         
247             case '7': // Delete other address
248                 this.getContactManager().doDeleteOtherAddress();
249                 break;
250
251             case '0': // Program exit
252                 this.getApplication().doShutdown();
253                 break;
254         
255             default:
256                 // @TODO throw own exception
257                 throw new UnhandledUserChoiceException(MessageFormat.format("Choice '{0}' not handled yet.", choice));
258         }
259     }
260
261     /**
262      * Asks the the user to enter a single character which must match validChars
263      * @param   validChars  Valid chars that are accepted
264      * @param   message     Message to user
265      * @return  Allowed character
266      */
267     @Override
268     public char enterChar (final char[] validChars, final String message) {
269         char input = 0;
270
271         // Sort array, else binarySearch() won't work
272         Arrays.sort(validChars);
273
274         // Keep asking until valid char has been entered
275         while (Arrays.binarySearch(validChars, input) < 0) {
276             // Output message
277             System.out.print(message);
278
279             // Read char
280             input = this.readChar();
281         }
282
283         // Return read char
284         return input;
285     }
286
287     /**
288      * Reads an integer (int) with a textural message from the user
289      * 
290      * @param minimum Minimum allowed number
291      * @param maximum Maximum allowed number
292      * @param message Messager to display in console
293      * @return 
294      */
295     @Override
296     public int enterInt (final int minimum, final int maximum, final String message) {
297         // Minimum should not be below zero
298         assert(minimum >= 0);
299         assert(maximum > minimum);
300
301         // Init input
302         int input = -1;
303
304         while ((input < minimum) || (input > maximum)) {
305             // Output message
306             System.out.print(message);
307
308             // Read integer from user
309             input = this.readInt();
310         }
311
312         // Return it
313         return input;
314     }
315
316     /**
317      * Reads a string of minimum and maximum length from the user
318      * 
319      * @param minLength Minimum length of the string to read
320      * @param maxLength Maximum length of the string to read
321      * @param message   Message to user
322      * @param allowEmpty Whether to allow empty string
323      * @return Entered string by user or null for empty strings
324      */
325     @Override
326     public String enterString (final int minLength, final int maxLength, final String message, final boolean allowEmpty) {
327         // Check on length, e.g. country codes are excactly 2 chars long
328         assert(maxLength >= minLength);
329
330         // Init input
331         String input = null;
332
333         // Check if it is to short or to long
334         while (((input == null) || ((input.length() < minLength) && (!allowEmpty))) || ((input.length() > 0) && (input.length() < minLength) && (allowEmpty)) || ((input instanceof String) && (input.length() > maxLength))) {
335             // Output message
336             System.out.print(message);
337
338             // Read line
339             input = this.readString();
340         }
341
342         // Return it
343         return input;
344     }
345
346     /**
347      * Returns a console menu item
348      * 
349      * @param accessKey Key to access the menu
350      * @param text Text to show to user
351      * @return A SelectableMenuItem
352      * @todo Make sure the access key is unique
353      */
354     @Override
355     public SelectableMenuItem getMenuItem (final char accessKey, final String text) {
356         // Return a new console menu item
357         return new ConsoleMenuItem(accessKey,text);
358     }
359
360     /**
361      * Inizializes this client
362      */
363     @Override
364     public void init () {
365         // Init contact manager here
366         this.initContactManager();
367
368         // Fill menu map
369         this.fillMenuMap();
370     }
371
372     /**
373      * Displays textural message to the user
374      * @param message
375      */
376     @Override
377     public void outputMessage (final String message) {
378         System.out.println(message);
379     }
380
381     /**
382      * Shows textural menu on console
383      */
384     @Override
385     public void showCurrentMenu () {
386         this.showMenu(this.getCurrentMenu());
387     }
388
389     /**
390      * Shows given menu entry to user
391      * 
392      * @param item Menu entry
393      */
394     @Override
395     public void showEntry (final SelectableMenuItem item) {
396         // Access key then text
397         this.outputMessage("[" + item.getAccessKey() + "] " + item.getText());
398     }
399
400     /**
401      * Shows a textural message to the user
402      */
403     @Override
404     public void showWelcome () {
405         this.outputMessage(MessageFormat.format("Welcome to {0}", AddressbookApplication.printableTitle()));
406         this.outputMessage("");
407         this.outputMessage("Copyright(c) 2015 by Roland Haeder, this is free software");
408         
409         // Debug message
410         this.getLogger().debug("Intro shown to user");
411     }
412
413     @Override
414     public void userChooseChangeContactData (final Contact contact) throws UnhandledUserChoiceException {
415         // Ask the user for editing [name], [a]ddress or [other] data
416         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) ");
417
418         // @TODO Get rid of this ugly switch block, too
419         switch (choice) {
420             case 'n': // Name data
421                 this.getContactManager().doChangeNameData(contact, this);
422                 break;
423
424             case 'a': // Address data
425                 this.getContactManager().doChangeAddressData(contact, this);
426                 break;
427
428             case 'o': // Other data
429                 this.getContactManager().doChangeOtherData(contact, this);
430                 break;
431
432             case 'x': // Exit this menu
433                 // Ignored as it should go back
434                 break;
435
436             default:
437                 // @TODO throw own exception
438                 throw new UnhandledUserChoiceException(MessageFormat.format("Choice '{0}' not handled yet.", choice));
439         }
440     }
441
442     /**
443      * Reads one character
444      * 
445      * @return A single character
446      */
447     private char readChar () {
448         // Read line
449         String input = this.scanner.nextLine();
450
451         // This must be only one character
452         if (input.length() != 1) {
453             // Return zero
454             return 0;
455         }
456
457         // Get char from first (and only) position
458         return input.charAt(0);
459     }
460
461     /**
462      * Reads an integer (int) from user
463      * 
464      * @return An integer number
465      */
466     private int readInt () {
467         // First read a string
468         String input = this.readString();
469
470         // Init number with invalid value
471         int num = -1;
472
473         // Parse number, this can be risky
474         try {
475             num = Integer.parseInt(input);
476         } catch (final NumberFormatException e) {
477             this.outputMessage("Bitte geben Sie nur Zahlen ein!");
478             this.getLogger().warn(MessageFormat.format("No numbers-only entered. input={0},message={1}", input, e.getMessage()));
479         }
480
481         // Return read number
482         return num;
483     }
484
485     /**
486      * Reads a string from a scanner until RETURN is pressed
487      * 
488      * @return Read string from scanner
489      */
490     private String readString () {
491         return this.scanner.nextLine();
492     }
493
494     /**
495      * Fills menu map with menu entries
496      */
497     @Override
498     protected final void fillMenuMap () {
499         // Initialize first (main) menu
500         Menu menu = new ConsoleMenu("main", this);
501         
502         // Add it
503         this.getMenus().put("main", menu);
504     }
505 }