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