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