]> git.mxchange.org Git - addressbook-swing.git/blob - Addressbook/src/org/mxchange/addressbook/client/console/ConsoleClient.java
Renamed some methods and auto-sorted them
[addressbook-swing.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.HashMap;\r
22 import java.util.Map;\r
23 import java.util.Scanner;\r
24 import org.mxchange.addressbook.UnhandledUserChoiceException;\r
25 import org.mxchange.addressbook.application.AddressbookApplication;\r
26 import org.mxchange.addressbook.application.Application;\r
27 import org.mxchange.addressbook.client.BaseClient;\r
28 import org.mxchange.addressbook.client.Client;\r
29 import org.mxchange.addressbook.contact.Contact;\r
30 import org.mxchange.addressbook.menu.Menu;\r
31 import org.mxchange.addressbook.menu.MenuTools;\r
32 import org.mxchange.addressbook.menu.console.ConsoleMenu;\r
33 import org.mxchange.addressbook.menu.item.SelectableMenuItem;\r
34 import org.mxchange.addressbook.menu.item.console.ConsoleMenuItem;\r
35 \r
36 /**\r
37  * A client for the console\r
38  *\r
39  * @author Roland Haeder\r
40  */\r
41 public class ConsoleClient extends BaseClient implements Client {\r
42     /**\r
43      * Menu system\r
44      */\r
45     private final Map<String, Menu> menus;\r
46 \r
47     /**\r
48      * Scanner instance for reading data from console input\r
49      */\r
50     private final Scanner scanner;\r
51 \r
52     /**\r
53      * Parameterless constructor\r
54      * @param application An instance of an Application class\r
55      */\r
56     public ConsoleClient (final Application application) {\r
57         super();\r
58 \r
59         // Set application instance\r
60         this.setApplication(application);\r
61 \r
62         // Init contact manager here\r
63         this.initContactManager(this);\r
64 \r
65         // Init scanner instance\r
66         this.scanner = new Scanner(System.in);\r
67 \r
68         // Init menu map\r
69         this.menus = new HashMap<>(10);\r
70 \r
71         // Fill menu map\r
72         this.fillConsoleMenuMap();\r
73     }\r
74 \r
75     /**\r
76      * Displays a textual address "box" of given contact\r
77      *\r
78      * @param contact Contact to show address for\r
79      * @todo Use mask\r
80      */\r
81     @Override\r
82     public void displayAddressBox (final Contact contact) {\r
83         // Simple display ...\r
84         // @todo Use mask\r
85         this.outputMessage("Strasse, PLZ Ort, Land: " + contact.getStreet() + "\n" + contact.getZipCode() + " " + contact.getCity() +  "\n" + contact.getCountryCode());\r
86     }\r
87 \r
88     /**\r
89      * Displays a textual name "box" of given contact\r
90      *\r
91      * @param contact Contact to show name for\r
92      */\r
93     @Override\r
94     public void displayNameBox (final Contact contact) {\r
95         // Get translated gender as the user may want to see "Mr.", "Mrs."\r
96         String gender = contact.getTranslatedGender();\r
97 \r
98         // Get company name\r
99         String companyName = contact.getCompanyName();\r
100 \r
101         // If it is empty/null, then assume private contact\r
102         if ((companyName == null) || (companyName.isEmpty())) {\r
103             // Now put all together: gender, surname, family name\r
104             // @todo Use mask\r
105             this.outputMessage("Anrede, Vorname, Name: " + gender + " " + contact.getSurname() + " " + contact.getFamilyName());\r
106         } else {\r
107             // Company contact\r
108             this.outputMessage("Firma: " + companyName + "\nAnsprechpartner: " + gender + " " + contact.getSurname() + " " + contact.getFamilyName());\r
109         }\r
110     }\r
111 \r
112     /**\r
113      * Displays a textual other data "box" of given contact\r
114      *\r
115      * @param contact Contact to show other data for\r
116      */\r
117     @Override\r
118     public void displayOtherDataBox (final Contact contact) {\r
119         // Cellphone and such ...\r
120         this.outputMessage("Telefonnumer: " + contact.getPhoneNumber() + "\nFaxnummer: " + contact.getFaxNumber() + "\nHandy: " + contact.getCellphoneNumber() + "\nKommentar:\n" + contact.getComment());\r
121     }\r
122 \r
123     @Override\r
124     public void doUserMenuChoice () throws UnhandledUserChoiceException {\r
125         // Get all access keys from menu\r
126         char[] accessKeys = MenuTools.getAccessKeysFromMenuMap(this.menus, this.getCurrentMenu());\r
127 \r
128         // Output textural message and ask for a char as input\r
129         char choice = this.enterChar(accessKeys, "Bitte Auswahl eingeben (0=Programm beenden): ");\r
130 \r
131         // @TODO Rewrite this ugly switch() block\r
132         switch (choice) {\r
133             case '1': // Enter/add own data\r
134                 this.getContactManager().doEnterOwnData();\r
135                 break;\r
136         \r
137             case '2': // Change own data\r
138                 this.getContactManager().changeOwnData();\r
139                 break;\r
140         \r
141             case '3': // Add new addess\r
142                 this.getContactManager().addOtherAddress();\r
143                 break;\r
144         \r
145             case '4': // Change other addess\r
146                 this.getContactManager().changeOtherAddress();\r
147                 break;\r
148         \r
149             case '5': // Delete other address\r
150                 this.getContactManager().deleteOtherAddress();\r
151                 break;\r
152 \r
153             case '0': // Program exit\r
154                 this.disableIsRunning();\r
155                 break;\r
156         \r
157             default:\r
158                 // @TODO throw own exception\r
159                 throw new UnhandledUserChoiceException("Choice '" + choice + "' not handled yet.");\r
160         }\r
161     }\r
162 \r
163     /**\r
164      * Asks the the user to enter a single character which must match validChars\r
165      * @param   validChars  Valid chars that are accepted\r
166      * @param   message     Message to user\r
167      * @return  Allowed character\r
168      */\r
169     @Override\r
170     public char enterChar (final char[] validChars, final String message) {\r
171         char input = 0;\r
172 \r
173         // Sort array, else binarySearch() won't work\r
174         Arrays.sort(validChars);\r
175 \r
176         // Keep asking until valid char has been entered\r
177         while (Arrays.binarySearch(validChars, input) < 0) {\r
178             // Output message\r
179             System.out.print(message);\r
180 \r
181             // Read char\r
182             input = this.readChar();\r
183         }\r
184 \r
185         // Return read char\r
186         return input;\r
187     }\r
188 \r
189     /**\r
190      * Reads an integer (int) with a textural message from the user\r
191      * \r
192      * @param minimum Minimum allowed number\r
193      * @param maximum Maximum allowed number\r
194      * @param message Messager to display in console\r
195      * @return \r
196      */\r
197     @Override\r
198     public int enterInt (final int minimum, final int maximum, final String message) {\r
199         // Minimum should not be below zero\r
200         assert(minimum >= 0);\r
201         assert(maximum > minimum);\r
202 \r
203         // Init input\r
204         int input = -1;\r
205 \r
206         while ((input < minimum) || (input > maximum)) {\r
207             // Output message\r
208             System.out.print(message);\r
209 \r
210             // Read integer from user\r
211             input = this.readInt();\r
212         }\r
213 \r
214         // Return it\r
215         return input;\r
216     }\r
217 \r
218     /**\r
219      * Reads a string of minimum and maximum length from the user\r
220      * \r
221      * @param minLength Minimum length of the string to read\r
222      * @param maxLength Maximum length of the string to read\r
223      * @param message   Message to user\r
224      * @param allowEmpty Whether to allow empty string\r
225      * @return Entered string by user or null for empty strings\r
226      */\r
227     @Override\r
228     public String enterString (final int minLength, final int maxLength, final String message, final boolean allowEmpty) {\r
229         // Check on length, e.g. country codes are excactly 2 chars long\r
230         assert(maxLength >= minLength);\r
231 \r
232         // Init input\r
233         String input = null;\r
234 \r
235         // Check if it is to short or to long\r
236         while (((input == null) || ((input.length() < minLength) && (!allowEmpty))) || ((input.length() > 0) && (input.length() < minLength) && (allowEmpty)) || ((input instanceof String) && (input.length() > maxLength))) {\r
237             // Output message\r
238             System.out.print(message);\r
239 \r
240             // Read line\r
241             input = this.readString();\r
242         }\r
243 \r
244         // Return it\r
245         return input;\r
246     }\r
247 \r
248     /**\r
249      * Returns a console menu item\r
250      * \r
251      * @param accessKey Key to access the menu\r
252      * @param text Text to show to user\r
253      * @return A SelectableMenuItem\r
254      * @todo Make sure the access key is unique\r
255      */\r
256     @Override\r
257     public SelectableMenuItem getMenuItem (final char accessKey, final String text) {\r
258         // Return a new console menu item\r
259         return new ConsoleMenuItem(accessKey,text);\r
260     }\r
261 \r
262     /**\r
263      * Displays textural message to the user\r
264      * @param message\r
265      */\r
266     @Override\r
267     public void outputMessage (final String message) {\r
268         System.out.println(message);\r
269     }\r
270 \r
271     /**\r
272      * Shows textural menu on console\r
273      */\r
274     @Override\r
275     public void showCurrentMenu () {\r
276         this.showMenu(this.getCurrentMenu());\r
277     }\r
278 \r
279     @Override\r
280     public void showEntry (final SelectableMenuItem item) {\r
281         // Access key then text\r
282         this.outputMessage("[" + item.getAccessKey() + "] " + item.getText());\r
283     }\r
284 \r
285     /**\r
286      * Shows a textural message to the user\r
287      */\r
288     @Override\r
289     public void showWelcome () {\r
290         this.outputMessage("Welcome to " + AddressbookApplication.APP_TITLE + " v" + AddressbookApplication.APP_VERSION);\r
291         this.outputMessage("");\r
292         this.outputMessage("Copyright(c) 2015 by Roland Haeder, this is free software");\r
293         \r
294         // Debug message\r
295         this.getLogger().debug("Intro shown to user");\r
296      }\r
297 \r
298     @Override\r
299     public void userChooseChangeContactData (final Contact contact) throws UnhandledUserChoiceException {\r
300         // Ask the user for editing [name], [a]ddress or [other] data\r
301         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
302         \r
303         // @TODO Get rid of this ugly switch block, too\r
304         switch (choice) {\r
305             case 'n': // Name data\r
306                 this.getContactManager().doChangeNameData(contact, this);\r
307                 break;\r
308                 \r
309             case 'a': // Address data\r
310                 this.getContactManager().doChangeAddressData(contact, this);\r
311                 break;\r
312                 \r
313             case 'o': // Other data\r
314                 this.getContactManager().doChangeOtherData(contact, this);\r
315                 break;\r
316                 \r
317             case 'x': // Exit this menu\r
318                 // Ignored as it should go back\r
319                 break;\r
320                 \r
321             default:\r
322                 // @TODO throw own exception\r
323                 throw new UnhandledUserChoiceException("Choice '" + choice + "' not handled yet.");\r
324         }\r
325     }\r
326 \r
327     /**\r
328      * Fills menu map with menu entries\r
329      */\r
330     private void fillConsoleMenuMap () {\r
331         // Initialize first (main) menu\r
332         Menu menu = new ConsoleMenu("main", this);\r
333 \r
334         // Add it\r
335         this.menus.put("main", menu);\r
336     }\r
337 \r
338     /**\r
339      * "Getter" for given menu type\r
340      * \r
341      * @param menuType Menu type instance to return\r
342      * @return Menu or null if not found\r
343      */\r
344     private Menu getMenu (final String menuType) {\r
345         // Default is not found\r
346         Menu menu = null;\r
347 \r
348         // Check array\r
349         if (this.menus.containsKey(menuType)) {\r
350             // Found!\r
351             menu = this.menus.get(menuType);\r
352         }\r
353         \r
354         // Return it\r
355         return menu;\r
356     }\r
357 \r
358     /**\r
359      * Reads one character\r
360      * \r
361      * @return A single character\r
362      */\r
363     private char readChar () {\r
364         // Read line\r
365         String input = this.scanner.nextLine();\r
366 \r
367         // This must be only one character\r
368         if (input.length() != 1) {\r
369             // Return zero\r
370             return 0;\r
371         }\r
372 \r
373         // Get char from first (and only) position\r
374         return input.charAt(0);\r
375     }\r
376 \r
377     /**\r
378      * Reads an integer (int) from user\r
379      * \r
380      * @return An integer number\r
381      */\r
382     private int readInt () {\r
383         // First read a string\r
384         String input = this.readString();\r
385 \r
386         // Init number with invalid value\r
387         int num = -1;\r
388 \r
389         // Parse number, this can be risky\r
390         try {\r
391             num = Integer.parseInt(input);\r
392         } catch (final NumberFormatException e) {\r
393             this.outputMessage("Bitte geben Sie nur Zahlen ein!");\r
394             this.getLogger().warn(MessageFormat.format("No numbers-only entered. input={0},message={1}", input, e.getMessage()));\r
395         }\r
396 \r
397         // Return read number\r
398         return num;\r
399     }\r
400 \r
401     /**\r
402      * Reads a string from a scanner until RETURN is pressed\r
403      * \r
404      * @return Read string from scanner\r
405      */\r
406     private String readString () {\r
407         return this.scanner.nextLine();\r
408     }\r
409 \r
410     /**\r
411      * Shows given menu\r
412      *\r
413      * @param menuType Given menu to show\r
414      */\r
415     private void showMenu (final String menuType) {\r
416         Menu menu = this.getMenu(menuType);\r
417         \r
418         // Is the menu set?\r
419         if (!(menu instanceof Menu)) {\r
420             // Not found\r
421             // @todo Own exception?\r
422             throw new NullPointerException("Menu '" + menuType + "' not found.");\r
423         }\r
424         \r
425         // Show menu\r
426         menu.show(this);\r
427     }\r
428 }\r