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