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