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