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