2 * Copyright (C) 2015 Roland Haeder
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.
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.
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/>.
17 package org.mxchange.addressbook.manager.contact;
19 import java.io.IOException;
20 import java.lang.reflect.InvocationTargetException;
21 import java.sql.SQLException;
22 import java.text.MessageFormat;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Iterator;
26 import java.util.List;
27 import org.mxchange.addressbook.client.AddressbookClient;
28 import org.mxchange.addressbook.database.frontend.contact.AddressbookContactDatabaseFrontend;
29 import org.mxchange.addressbook.database.frontend.contact.AddressbookContactFrontend;
30 import org.mxchange.addressbook.exceptions.ContactAlreadyAddedException;
31 import org.mxchange.jcore.client.Client;
32 import org.mxchange.jcore.contact.Contact;
33 import org.mxchange.jcore.contact.Gender;
34 import org.mxchange.jcore.exceptions.BadTokenException;
35 import org.mxchange.jcore.exceptions.CorruptedDatabaseFileException;
36 import org.mxchange.jcore.exceptions.UnhandledUserChoiceException;
37 import org.mxchange.jcore.exceptions.UnsupportedDatabaseBackendException;
38 import org.mxchange.jcore.manager.BaseManager;
41 * A manager for contacts.
43 * @author Roland Haeder
46 public class AddressbookContactManager extends BaseManager implements ManageableAddressbookContact {
51 private final List<String> columnNames;
54 * A AddressbookContactFrontend instance
56 private final AddressbookContactFrontend contactDatabase;
59 * Translated column name list
61 private final List<String> translatedColumnNames;
64 * Constructor which accepts maxContacts for maximum (initial) contacts and
67 * @param client Client instance to use
68 * @throws org.mxchange.jcore.exceptions.UnsupportedDatabaseBackendException If the configured database backend is not supported
69 * @throws java.sql.SQLException If an SQL error occurs
71 public AddressbookContactManager (final Client client) throws UnsupportedDatabaseBackendException, SQLException {
73 this.getLogger().trace(MessageFormat.format("client={1} - CALLED!", client)); //NOI18N
75 // Make sure all parameters are set correctly
78 throw new NullPointerException("client is null"); //NOI18N
81 // Set client instance
82 this.setClient(client);
84 // Init database connection
85 this.contactDatabase = new AddressbookContactDatabaseFrontend(this);
88 this.columnNames = new ArrayList<>(15);
89 this.translatedColumnNames = new ArrayList<>(15);
92 this.fillColumnNamesFromBundle();
95 //* NOISY-DEBUG: */ this.getLogger().debug("client=" + client);
99 * Adds given Contact instance to list
101 * @param contact Contact instance to add
104 public void addContact (final Contact contact) throws ContactAlreadyAddedException {
106 this.getLogger().trace(MessageFormat.format("contact={0} - CALLED!", contact)); //NOI18N
108 // Contact instance must not be null
109 if (contact == null) {
111 throw new NullPointerException("contact is null"); //NOI18N
115 this.getContactDatabase().addContact(contact);
118 this.getLogger().trace("EXIT!"); //NOI18N
122 * Let the user add a new other address
125 public void doAddOtherAddress () {
126 throw new UnsupportedOperationException("Not supported yet."); //NOI18N
130 * Let the user change address data
132 * @param contact Instance to change data
135 public void doChangeAddressData (final Contact contact) {
137 this.getLogger().trace(MessageFormat.format("contact={0} CALLED!", contact)); //NOI18N
139 // Contact must not be null
140 if (contact == null) {
142 throw new NullPointerException("contact is null"); //NOI18N
145 // Get and cast client instance
146 AddressbookClient client = (AddressbookClient) this.getClient();
148 // First display it again
149 client.displayAddressBox(contact);
152 if (contact.isOwnContact()) {
153 // Deligate to client
154 client.doChangeOwnAddressData(contact);
156 // Other contact's address data to change
157 throw new UnsupportedOperationException("Changing contact entries not finished."); //NOI18N
161 this.getLogger().trace("EXIT!"); //NOI18N
165 * Let the user change "name data"
167 * @param contact Instance to change data
170 public void doChangeNameData (final Contact contact) {
172 this.getLogger().trace(MessageFormat.format("contact={0} CALLED!", contact)); //NOI18N
174 // Contact must not be null
175 if (contact == null) {
177 throw new NullPointerException("contact is null"); //NOI18N
180 // Get and cast client instance
181 AddressbookClient client = (AddressbookClient) this.getClient();
183 // First display them again
184 client.displayNameBox(contact);
187 if (contact.isOwnContact()) {
189 client.doChangeOwnNameData(contact);
191 // Then re-ask them ...
192 throw new UnsupportedOperationException("Changing contact entries not finished."); //NOI18N
196 this.getLogger().trace("EXIT!"); //NOI18N
200 * Let the user change other address
203 public void doChangeOtherAddress () {
204 throw new UnsupportedOperationException("Not supported yet."); //NOI18N
208 * Let the user change other data
210 * @param contact Instance to change data
211 * @todo Didn't handle birthday
214 public void doChangeOtherData (final Contact contact) {
216 this.getLogger().trace(MessageFormat.format("contact={0} CALLED!", contact)); //NOI18N
218 // Contact must not be null
219 if (contact == null) {
221 throw new NullPointerException("contact is null"); //NOI18N
224 // Get and cast client instance
225 AddressbookClient client = (AddressbookClient) this.getClient();
227 // First display them again
228 client.displayOtherDataBox(contact);
231 if (contact.isOwnContact()) {
233 client.doChangeOwnOtherData(contact);
235 // Then re-ask them ...
236 throw new UnsupportedOperationException("Changing contact entries not finished."); //NOI18N
240 this.getLogger().trace("EXIT!"); //NOI18N
244 * Allows the user to change his/her own data
247 public void doChangeOwnData () throws IOException , BadTokenException{
249 this.getLogger().trace("CALLED!"); //NOI18N
252 * First check if the user has registered own contact, before that
253 * nothing can be changed.
255 if (!this.isOwnContactAdded()) {
257 this.getClient().outputMessage("Sie haben noch nicht Ihre Daten eingegeben."); //NOI18N
259 // Skip any below code
264 Contact contact = this.getOwnContact();
267 assert (contact instanceof Contact);
270 contact.show(this.getClient());
272 // Get and cast client instance
273 AddressbookClient client = (AddressbookClient) this.getClient();
276 // Ask user what to change
277 client.userChooseChangeContactData(contact);
278 } catch (final UnhandledUserChoiceException ex) {
279 this.getLogger().catching(ex);
283 this.getLogger().trace("EXIT!"); //NOI18N
287 * Let the user delete other address
290 public void doDeleteOtherAddress () {
291 throw new UnsupportedOperationException("Not supported yet."); //NOI18N
295 * Asks user for own data
298 public void doEnterOwnData () throws ContactAlreadyAddedException, IOException , BadTokenException {
300 this.getLogger().trace("CALLED!"); //NOI18N
302 // Is own contact already added?
303 if (this.isOwnContactAdded()) {
304 // Don't continue here
305 throw new ContactAlreadyAddedException();
308 // Get and cast client instance
309 AddressbookClient client = (AddressbookClient) this.getClient();
311 // Deligate this call to the client
312 Contact contact = client.doEnterOwnData();
315 if (contact instanceof Contact) {
316 // Add it to contact "book"
317 this.registerContact(contact);
321 this.getLogger().trace("EXIT!"); //NOI18N
325 public void doListContacts () {
326 throw new UnsupportedOperationException("Not supported yet."); //NOI18N
330 public void doSearchContacts () {
331 throw new UnsupportedOperationException("Not supported yet."); //NOI18N
335 * Shuts down this contact manager
337 * @throws java.sql.SQLException If an SQL error occurs
338 * @throws java.io.IOException If an IO error occurs
341 public void doShutdown () throws SQLException, IOException {
343 this.getLogger().trace("CALLED!"); //NOI18N
345 // Shut down the database layer
346 this.getContactDatabase().doShutdown();
349 this.getLogger().trace("EXIT!"); //NOI18N
353 * Asks the user for his/her cellphone number
355 * @return User's cellphone number
358 public String enterOwnCellNumber () {
360 this.getLogger().trace("CALLED!"); //NOI18N
362 // Get and cast client instance
363 AddressbookClient client = (AddressbookClient) this.getClient();
365 return client.enterString(5, 30, "Bitte geben Sie Ihre Handynummer an: ", true);
369 * Asks the user for his/her city's name
371 * @return City's name of the user
374 public String enterOwnCity () {
376 this.getLogger().trace("CALLED!"); //NOI18N
378 // Get and cast client instance
379 AddressbookClient client = (AddressbookClient) this.getClient();
381 return client.enterString(3, 50, "Bitte geben Sie Ihre Wohnort ein: ", false);
385 * Asks the user for his/her city's name
387 * @return City's name of the user
390 public String enterOwnComment () {
392 this.getLogger().trace("CALLED!"); //NOI18N
394 // Get and cast client instance
395 AddressbookClient client = (AddressbookClient) this.getClient();
397 return client.enterString(0, 100, "Kommentar zu Ihrem Eintrag: ", true);
401 * Asks the user for his/her company name
403 * @return User's company name
406 public String enterOwnCompanyName () {
408 this.getLogger().trace("CALLED!"); //NOI18N
410 // Get and cast client instance
411 AddressbookClient client = (AddressbookClient) this.getClient();
413 return client.enterString(5, 50, "Bitte geben Sie Ihre Firmenbezeichnung ein: ", true);
417 * Asks user for his/her own country code
419 * @return User's own country code
422 public String enterOwnCountryCode () {
424 this.getLogger().trace("CALLED!"); //NOI18N
426 // Get and cast client instance
427 AddressbookClient client = (AddressbookClient) this.getClient();
429 return client.enterString(2, 2, "Bitte geben Sie den zweistelligen Ländercode von Ihrem Land ein: ", false).toUpperCase();
433 * Asks user for his/her own country code
435 * @return User's own country code
438 public String enterOwnEmailAddress () {
440 this.getLogger().trace("CALLED!"); //NOI18N
442 // Get and cast client instance
443 AddressbookClient client = (AddressbookClient) this.getClient();
445 return client.enterString(10, 50, "Bitte geben Sie Ihre Email-Adresse ein: ", true);
449 * Asks the user for family name
451 * @return Family name of the user
454 public String enterOwnFamilyName () {
456 this.getLogger().trace("CALLED!"); //NOI18N
458 // Get and cast client instance
459 AddressbookClient client = (AddressbookClient) this.getClient();
461 return client.enterString(2, 50, "Bitte geben Sie Ihren Nachnamen ein: ", false);
465 * Asks the user for family name
467 * @return Family name of the user
470 public String enterOwnFaxNumber () {
472 this.getLogger().trace("CALLED!"); //NOI18N
474 // Get and cast client instance
475 AddressbookClient client = (AddressbookClient) this.getClient();
477 return client.enterString(5, 30, "Bitte geben Sie Ihre Faxnummer an: ", true);
481 * Asks the user for gender, until a valid has been entered
483 * @return Gender of the user
486 public Gender enterOwnGender () {
488 this.getLogger().trace("CALLED!"); //NOI18N
490 // Get and cast client instance
491 AddressbookClient client = (AddressbookClient) this.getClient();
493 return client.enterGender("Bitte geben Sie die Anrede ein: (M=Herr, F=Frau, C=Firma): ");
497 * Asks the user for phone number
499 * @return Phone number of the user
502 public String enterOwnPhoneNumber () {
504 this.getLogger().trace("CALLED!"); //NOI18N
506 // Get and cast client instance
507 AddressbookClient client = (AddressbookClient) this.getClient();
509 return client.enterString(5, 30, "Bitte geben Sie Ihre Telefonnummer an: ", true);
513 * Asks the user for own street (including number)
515 * @return Own street an number
518 public String enterOwnStreet () {
520 this.getLogger().trace("CALLED!"); //NOI18N
522 // Get and cast client instance
523 AddressbookClient client = (AddressbookClient) this.getClient();
525 return client.enterString(5, 50, "Bitte geben Sie Ihre Strasse und Hausnummer ein: ", false);
529 * Asks the user for surname
531 * @return Surname of the user
534 public String enterOwnSurname () {
536 this.getLogger().trace("CALLED!"); //NOI18N
538 // Get and cast client instance
539 AddressbookClient client = (AddressbookClient) this.getClient();
541 return client.enterString(2, 50, "Bitte geben Sie Ihren Vornamen ein: ", false);
545 * Asks the user for own ZIP code
550 public int enterOwnZipCode () {
552 this.getLogger().trace("CALLED!"); //NOI18N
554 // Get and cast client instance
555 AddressbookClient client = (AddressbookClient) this.getClient();
557 return client.enterInt(0, 99_999, "Bitte geben Sie Ihre Postleitzahl ein: ");
561 public final int getColumnCount () {
562 assert (this.columnNames instanceof List) : "this.columnNames is not initialized"; //NOI18N
564 return this.columnNames.size();
568 * Getter for column name at given index.
570 * @param columnIndex Column index
571 * @return Database column name
574 public String getColumnName (final int columnIndex) {
575 assert (this.columnNames instanceof List) : "this.columnNames is not initialized"; //NOI18N
577 // Get column name at index
578 return this.columnNames.get(columnIndex);
582 * Getter for translated column name at given index.
584 * @param columnIndex Column index
585 * @return Human-readable column name
588 public String getTranslatedColumnName (final int columnIndex) {
589 assert (this.translatedColumnNames instanceof List) : "this.translatedColumnNames is not initialized"; //NOI18N
591 // Get column name at index
592 return this.translatedColumnNames.get(columnIndex);
596 * Somewhat "getter" for value from given row and column index
598 * @param rowIndex Row index
599 * @param columnIndex Column index
600 * @return Value from given row/column
603 public Object getValueFromRowColumn (final int rowIndex, final int columnIndex) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
605 this.getLogger().trace(MessageFormat.format("rowIndex={0},columnIndex={1} CALLED!", rowIndex, columnIndex));
607 // Then get specific row from database which is a Contact instance
608 Contact contact = this.getContactDatabase().readSingleContact(rowIndex);
611 this.getLogger().debug(MessageFormat.format("contact={0}", contact));
613 // It may return null
614 if (contact == null) {
616 this.getLogger().warn("contact is null - returning null ...");
620 // Convert column index -> name
621 String columnName = this.getColumnName(columnIndex);
624 this.getLogger().debug(MessageFormat.format("columnName={0}", columnName));
626 // Now get that column
629 value = contact.getValueFromColumn(columnName);
630 } catch (final IllegalArgumentException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
631 this.abortProgramWithException(ex);
635 this.getLogger().trace(MessageFormat.format("value={0} - EXIT!", value));
642 * Checks whether own contact is already added by checking all entries for
645 * @return Whether own contact is already added
648 public boolean isOwnContactAdded () throws IOException, BadTokenException {
650 this.getLogger().trace("CALLED!"); //NOI18N
653 boolean isAdded = false;
656 // Deligate this call to frontend
657 isAdded = this.getContactDatabase().isOwnContactFound();
658 } catch (final SQLException | IOException | BadTokenException | CorruptedDatabaseFileException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
659 // Something bad happened
660 this.abortProgramWithException(ex);
664 this.getLogger().trace(MessageFormat.format("isAdded={0} : EXIT!", isAdded)); //NOI18N
671 * Adds given contact to address book and flushes all entries to database
673 * @param contact Contact being added
674 * @todo Add check for book size
677 public void registerContact (final Contact contact) {
679 this.getLogger().trace(MessageFormat.format("contact={0} CALLED!", contact)); //NOI18N
682 if (contact == null) {
684 throw new NullPointerException("contact is null"); //NOI18N
688 /* NOISY-DEBUG: */ this.getLogger().debug(MessageFormat.format("Adding '{0}' '{1}' at pos '{2}' ...", contact.getSurname(), contact.getFamilyName(), this.size())); //NOI18N
690 // Check if contact is found
691 if (this.getContactDatabase().isContactFound(contact)) {
692 // Contact already added
693 // @todo Do something here
694 } else if ((contact.isOwnContact()) && (this.isOwnContactAdded())) {
695 // Own contact already added
696 // @todo Do something
699 // Add contact to internal list
700 this.addContact(contact);
701 } catch (final ContactAlreadyAddedException | BadTokenException | SQLException | IOException | CorruptedDatabaseFileException | NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
703 this.abortProgramWithException(ex);
707 this.getLogger().trace("EXIT!"); //NOI18N
713 * @return size of contact "book"
716 public final int size () {
721 size = this.getContactDatabase().getContactsCount();
722 } catch (final SQLException ex) {
723 // Something happened
724 this.abortProgramWithException(ex);
732 * Fills the column names array with strings from bundle
734 private void fillColumnNamesFromBundle () {
735 assert (this.columnNames instanceof List) : "this.columnNames is not initialized"; //NOI18N
736 assert (this.translatedColumnNames instanceof List) : "this.translatedColumnNames is not initialized"; //NOI18N
739 this.getLogger().trace("CALLED!"); //NOI18N
741 // First get an iterator from key set to iterate over
742 Iterator<String> iterator = this.getBundle().keySet().iterator();
744 // Then iterate over all
745 while (iterator.hasNext()) {
747 String key = iterator.next();
749 // Does the key start with AddressbookContactManager.columnName ?
750 if (key.startsWith("ContactManager.columnName")) { //NOI18N
751 // This is the wanted entry.
752 this.getLogger().debug(MessageFormat.format("key={0}", key)); //NOI18N
754 // Convert string to array based on delimiter '.'
755 String[] tokens = this.getArrayFromString(key, ".", 4);
757 // Token array must contain 4 elements (AddressbookContactManager.columnName.foo.text)
758 assert(tokens.length == 4) : MessageFormat.format("Array tokens contains not 4 elements: {0}", Arrays.toString(tokens));
760 // Get pre-last element
761 String columnName = tokens[tokens.length - 2];
764 this.getLogger().debug(MessageFormat.format("columnName={0} - adding ...", columnName));
767 this.columnNames.add(columnName);
768 this.translatedColumnNames.add(this.getBundle().getString(key));
773 this.getLogger().trace(MessageFormat.format("getColumnCount()={0}: EXIT!", this.getColumnCount())); //NOI18N
777 * A AddressbookContactFrontend instance
779 * @return the database
781 private AddressbookContactFrontend getContactDatabase () {
782 return this.contactDatabase;
786 * "Getter" for own contact instance or null if not found
788 * @return Contact instance or null
790 private Contact getOwnContact () {
792 this.getLogger().trace("CALLED!"); //NOI18N
794 // Deligate this call to database frontend
795 Contact contact = this.getContactDatabase().getOwnContact();
798 this.getLogger().trace(MessageFormat.format("contact={0} - EXIT!", contact)); //NOI18N
800 // Return instance or null