]> git.mxchange.org Git - jfinancials-lib.git/blob - Addressbook/src/org/mxchange/addressbook/client/console/ConsoleClient.java
Introduced updateAddressData() + changing own "address data" is basicly finished
[jfinancials-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.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 doUserChangeAdressChoice (final Contact contact) throws UnhandledUserChoiceException {\r
125         // Ask the user for editing [name], [a]ddress or [other] data\r
126         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
127 \r
128         // @TODO Get rid of this ugly switch block, too\r
129         switch (choice) {\r
130             case 'n': // Name data\r
131                 this.getContactManager().changeNameData(contact, this);\r
132                 break;\r
133 \r
134             case 'a': // Address data\r
135                 this.getContactManager().changeAddressData(contact, this);\r
136                 break;\r
137 \r
138             case 'o': // Other data\r
139                 this.getContactManager().changeOtherData(contact, this);\r
140                 break;\r
141 \r
142             case 'x': // Exit this menu\r
143                 // Ignored as it should go back\r
144                 break;\r
145 \r
146             default:\r
147                 // @TODO throw own exception\r
148                 throw new UnhandledUserChoiceException("Choice '" + choice + "' not handled yet.");\r
149         }\r
150     }\r
151 \r
152     @Override\r
153     public void doUserMenuChoice () throws UnhandledUserChoiceException {\r
154         // Get all access keys from menu\r
155         char[] accessKeys = MenuTools.getAccessKeysFromMenuMap(this.menus, this.getCurrentMenu());\r
156 \r
157         // Output textural message and ask for a char as input\r
158         char choice = this.enterChar(accessKeys, "Bitte Auswahl eingeben (0=Programm beenden): ");\r
159 \r
160         // @TODO Rewrite this ugly switch() block\r
161         switch (choice) {\r
162             case '1': // Enter/add own data\r
163                 this.getContactManager().enterOwnData();\r
164                 break;\r
165         \r
166             case '2': // Change own data\r
167                 this.getContactManager().changeOwnData();\r
168                 break;\r
169         \r
170             case '3': // Add new addess\r
171                 this.getContactManager().addOtherAddress();\r
172                 break;\r
173         \r
174             case '4': // Change other addess\r
175                 this.getContactManager().changeOtherAddress();\r
176                 break;\r
177         \r
178             case '5': // Delete other address\r
179                 this.getContactManager().deleteOtherAddress();\r
180                 break;\r
181 \r
182             case '0': // Program exit\r
183                 this.disableIsRunning();\r
184                 break;\r
185         \r
186             default:\r
187                 // @TODO throw own exception\r
188                 throw new UnhandledUserChoiceException("Choice '" + choice + "' not handled yet.");\r
189         }\r
190     }\r
191 \r
192     /**\r
193      * Asks the the user to enter a single character which must match validChars\r
194      * @param   validChars  Valid chars that are accepted\r
195      * @param   message     Message to user\r
196      * @return  Allowed character\r
197      */\r
198     @Override\r
199     public char enterChar (final char[] validChars, final String message) {\r
200         char input = 0;\r
201 \r
202         // Sort array, else binarySearch() won't work\r
203         Arrays.sort(validChars);\r
204 \r
205         // Keep asking until valid char has been entered\r
206         while (Arrays.binarySearch(validChars, input) < 0) {\r
207             // Output message\r
208             System.out.print(message);\r
209 \r
210             // Read char\r
211             input = this.readChar();\r
212         }\r
213 \r
214         // Return read char\r
215         return input;\r
216     }\r
217 \r
218     /**\r
219      * Reads an integer (int) with a textural message from the user\r
220      * \r
221      * @param minimum Minimum allowed number\r
222      * @param maximum Maximum allowed number\r
223      * @param message Messager to display in console\r
224      * @return \r
225      */\r
226     @Override\r
227     public int enterInt (final int minimum, final int maximum, final String message) {\r
228         // Minimum should not be below zero\r
229         assert(minimum >= 0);\r
230         assert(maximum > minimum);\r
231 \r
232         // Init input\r
233         int input = -1;\r
234 \r
235         while ((input < minimum) || (input > maximum)) {\r
236             // Output message\r
237             System.out.print(message);\r
238 \r
239             // Read integer from user\r
240             input = this.readInt();\r
241         }\r
242 \r
243         // Return it\r
244         return input;\r
245     }\r
246 \r
247     /**\r
248      * Reads a string of minimum and maximum length from the user\r
249      * \r
250      * @param minLength Minimum length of the string to read\r
251      * @param maxLength Maximum length of the string to read\r
252      * @param message   Message to user\r
253      * @param allowEmpty Whether to allow empty string\r
254      * @return Entered string by user or null for empty strings\r
255      */\r
256     @Override\r
257     public String enterString (final int minLength, final int maxLength, final String message, final boolean allowEmpty) {\r
258         // Check on length, e.g. country codes are excactly 2 chars long\r
259         assert(maxLength >= minLength);\r
260 \r
261         // Init input\r
262         String input = null;\r
263 \r
264         // Check if it is to short or to long\r
265         while (((input == null) || ((input.length() < minLength) && (!allowEmpty))) || ((input.length() > 0) && (input.length() < minLength) && (allowEmpty)) || ((input instanceof String) && (input.length() > maxLength))) {\r
266             // Output message\r
267             System.out.print(message);\r
268 \r
269             // Read line\r
270             input = this.readString();\r
271         }\r
272 \r
273         // Return it\r
274         return input;\r
275     }\r
276 \r
277     /**\r
278      * Returns a console menu item\r
279      * \r
280      * @param accessKey Key to access the menu\r
281      * @param text Text to show to user\r
282      * @return A SelectableMenuItem\r
283      * @todo Make sure the access key is unique\r
284      */\r
285     @Override\r
286     public SelectableMenuItem getMenuItem (final char accessKey, final String text) {\r
287         // Return a new console menu item\r
288         return new ConsoleMenuItem(accessKey,text);\r
289     }\r
290 \r
291     /**\r
292      * Displays textural message to the user\r
293      * @param message\r
294      */\r
295     @Override\r
296     public void outputMessage (final String message) {\r
297         System.out.println(message);\r
298     }\r
299 \r
300     /**\r
301      * Shows textural menu on console\r
302      */\r
303     @Override\r
304     public void showCurrentMenu () {\r
305         this.showMenu(this.getCurrentMenu());\r
306     }\r
307 \r
308     @Override\r
309     public void showEntry (final SelectableMenuItem item) {\r
310         // Access key then text\r
311         this.outputMessage("[" + item.getAccessKey() + "] " + item.getText());\r
312     }\r
313 \r
314     /**\r
315      * Shows a textural message to the user\r
316      */\r
317     @Override\r
318     public void showWelcome () {\r
319          this.outputMessage("Welcome to " + AddressbookApplication.APP_TITLE + " v" + AddressbookApplication.APP_VERSION);\r
320          this.outputMessage("");\r
321          this.outputMessage("Copyright(c) 2015 by Roland Haeder, this is free software");\r
322          \r
323          // Debug message\r
324          this.getLogger().debug("Intro shown to user");\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