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