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